分析案例
竖屏下,从 Launcher 启动一个横屏 app。
app 很简单,就是从 Android Studio 创建一个 project,然后在 AndroidManifest.xml 中,把 MainActivity 的方向声明为横屏,如下
<activity
android:name=".MainActivity"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
第一阶段启动
第一阶段启动,从 Launcher 点击 app 图标开始
// QuickStepLauncher.java
@Override
public View.OnClickListener getItemOnClickListener() {
return this::onItemClicked;
}
protected void onItemClicked(View view) {
if (!mSplitToWorkspaceController.handleSecondAppSelectionForSplit(view)) {
// 调用到 ItemClickHandler#onClick()
QuickstepLauncher.super.getItemOnClickListener().onClick(view);
}
}
// ItemClickHandler.java
private static void onClick(View v) {
// ...
// 通过 View 的 Context, 强转 Launcher
Launcher launcher = Launcher.getLauncher(v.getContext());
if (!launcher.getWorkspace().isFinishedSwitchingState()) return;
Object tag = v.getTag();
if (tag instanceof WorkspaceItemInfo) { // 点击 workspace 区域图标
onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher);
} // ...
}
public static void onClickAppShortcut(View v, WorkspaceItemInfo shortcut, Launcher launcher) {
// ...
startAppShortcutOrInfoActivity(v, shortcut, launcher);
}
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
Intent intent;
if (item instanceof ItemInfoWithIcon
&& (((ItemInfoWithIcon) item).runtimeStatusFlags
& ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
} else {
// WorkspaceItemInfo 获取启动 app 的 Intent
intent = item.getIntent();
}
// ...
if (v != null && launcher.supportsAdaptiveIconAnimation(v)
&& !item.shouldUseBackgroundAnimation()) {
// 预加载 view 的 icon,保存到 FloatingIconView#sIconLoadResult
// Preload the icon to reduce latency b/w swapping the floating view with the original.
FloatingIconView.fetchIcon(launcher, v, item, true /* isOpening */);
}
// 由 Launcher 执行启动
// 子类 QuickStepLauncher 有复写,但是最终由基类 ActivityContext 实现核心逻辑
launcher.startActivitySafely(v, intent, item);
}
// ActivityContext.java
default RunnableList startActivitySafely(
View v, Intent intent, @Nullable ItemInfo item) {
// 强转 Context
Context context = (Context) this;
// ..
// 重点:创建启动 Activity 时附带的参数
// Launcher 的子类 QuickstepLauncher 复写了 getActivityLaunchOptions()
ActivityOptionsWrapper options = v != null ? getActivityLaunchOptions(v, item)
: makeDefaultActivityOptions(item != null && item.animationType == DEFAULT_NO_ICON
? SPLASH_SCREEN_STYLE_SOLID_COLOR : -1 /* SPLASH_SCREEN_STYLE_UNDEFINED */);
UserHandle user = item == null ? null : item.user;
Bundle optsBundle = options.toBundle();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (v != null) {
// intent 保存了 view bounds
intent.setSourceBounds(Utilities.getViewBounds(v));
}
try {
// item.itemt.Type 为 ITEM_TYPE_APPLICATION
boolean isShortcut = (item instanceof WorkspaceItemInfo)
&& (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& !((WorkspaceItemInfo) item).isPromise();
if (isShortcut) {
} else if (user == null || user.equals(Process.myUserHandle())) {
// 由 Context 启动 activity
context.startActivity(intent, optsBundle);
} else {
}
// ...
return options.onEndCallback;
} catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
// ...
}
return null;
}
从 Launcher 启动 app 的原理,就是通过 Context#startActivity() 启动指定 Activity。
很多人可能关心传入的 Bundle 参数到底包含哪些数据,这里仅仅展示下,不做分析,因为目前还用不到。
// QuickStepLauncher.java
public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
// 重点:创建 ActivityOptionsWrapper
ActivityOptionsWrapper activityOptions =
mAppTransitionManager.hasControlRemoteAppTransitionPermission()
? mAppTransitionManager.getActivityLaunchOptions(v)
: super.getActivityLaunchOptions(v, item);
if (mLastTouchUpTime > 0) {
activityOptions.options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER,
mLastTouchUpTime);
if (item != null && (item.animationType == DEFAULT_NO_ICON
|| item.animationType == VIEW_BACKGROUND)) {
} else {
// 启动窗口使用 icon
activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
}
// 保存 display id
activityOptions.options.setLaunchDisplayId(
(v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
: Display.DEFAULT_DISPLAY);
// 保存 cookie
addLaunchCookie(item, activityOptions.options);
return activityOptions;
}
// QuickstepTransitionManager.java
public ActivityOptionsWrapper getActivityLaunchOptions(View v) {
boolean fromRecents = isLaunchingFromRecents(v, null /* targets */);
RunnableList onEndCallback = new RunnableList();
// Handle the case where an already visible task is launched which results in no transition
TaskRestartedDuringLaunchListener restartedListener =
new TaskRestartedDuringLaunchListener();
restartedListener.register(onEndCallback::executeAllAndDestroy);
onEndCallback.add(restartedListener::unregister);
// 远程动画的真正执行者
mAppLaunchRunner = new AppLaunchAnimationRunner(v, onEndCallback);
ItemInfo tag = (ItemInfo) v.getTag();
if (tag != null && tag.shouldUseBackgroundAnimation()) {
}
// RemoteAnimationRunnerCompat 是为了兼容新旧两种动画而设计的类
// 它把远程动画交给 mAppLaunchRunner 去执行
RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(
mHandler, mAppLaunchRunner, true /* startAtFrontOfQueue */);
// Note that this duration is a guess as we do not know if the animation will be a
// recents launch or not for sure until we know the opening app targets.
long duration = fromRecents
? RECENTS_LAUNCH_DURATION
: APP_LAUNCH_DURATION;
long statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY;
ActivityOptions options = ActivityOptions.makeRemoteAnimation(
new RemoteAnimationAdapter(runner, duration, statusBarTransitionDelay),
new RemoteTransition(runner.toRemoteTransition(),
mLauncher.getIApplicationThread(), "QuickstepLaunch"));
return new ActivityOptionsWrapper(options, onEndCallback);
}
ATMS
// ActivityTaskManagerService.java
public final int startActivity(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions) {
// 增加了最后一个参数 userId
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
public int startActivityAsUser(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions, int userId) {
// 增加了最后一个参数 validateIncomingUser,值为 true
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
true /*validateIncomingUser*/);
}
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
// app 端传过来的参数是 Bundle 类型,并且是序列化的,因此无法打印
// 在服务端,需要把它转换为 ActivityOptions 才能打印 app 端传入的数据
// 这里更进一步,把 ActivityOptions 包装成 SafeActivityOptions,为的是检测调用方的权限
final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions);
// ...
// 把启动参数包装成 ActivityStart#mRequest ,并通过 ActivityStarter 来启动 activity
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller) // 指向 launcher
.setCallingPackage(callingPackage) // com.android.launcher
.setCallingFeatureId(callingFeatureId) // null
.setResolvedType(resolvedType) // 这是 mime type,目前是 null
.setResultTo(resultTo) // 指向 launcher
.setResultWho(resultWho) // null
// 注意,这个请求码是 -1,也就是说 launcher 不需要知道启动结果
.setRequestCode(requestCode)
.setStartFlags(startFlags) // 0
.setProfilerInfo(profilerInfo) // null
.setActivityOptions(opts) // 这个是启动 Activity 传入的数据,不为 null
.setUserId(userId)
.execute();
}
ATMS 把启动 Activity 的参数保存到了 ActivityStart#mRequest,然后交给 ActivityStarter 继续执行启动 Activity 流程。
ActivityStarter
// ActivityStarter.java
/**
* Resolve necessary information according the request parameters provided earlier, and execute
* the request which begin the journey of starting an activity.
* @return The starter result.
*/
int execute() {
try {
// ...
// 1.解析 Activity 信息,并保存到 mRequest.activityInfo
if (mRequest.activityInfo == null) {
mRequest.resolveActivity(mSupervisor);
}
// ...
int res;
synchronized (mService.mGlobalLock) {
// ...
try {
// 2.执行activity启动请求
res = executeRequest(mRequest);
} finally {
mRequest.logMessage.append(" result code=").append(res);
// 这里输出的就是著名的 START u0 的 log
Slog.i(TAG, mRequest.logMessage.toString());
mRequest.logMessage.setLength(0);
}
// ...
return getExternalResult(res);
}
} finally {
onExecutionComplete();
}
}
根据注释所说,这一步主要就是解析一些必要信息,然后执行请求。
executeRequest()
// ActivityStarter.java
/**
* Executing activity start request and starts the journey of starting an activity. Here
* begins with performing several preliminary checks. The normally activity launch flow will
* go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
*/
private int executeRequest(Request request) {
// 省略启动前检查的代码
// ...
// 构造 START u0 的 log
if (err == ActivityManager.START_SUCCESS) {
request.logMessage.append("START u").append(userId).append(" {")
.append(intent.toShortString(true, true, true, false))
.append("} with ").append(launchModeToString(launchMode))
.append(" from uid ").append(callingUid);
if (callingUid != realCallingUid
&& realCallingUid != Request.DEFAULT_REAL_CALLING_UID) {
request.logMessage.append(" (realCallingUid=").append(realCallingUid).append(")");
}
}
// ...
// 创建 ActivityRecord
final ActivityRecord r = new ActivityRecord.Builder(mService)
.setCaller(callerApp) // 指向 launcher 进程
.setLaunchedFromPid(callingPid)
.setLaunchedFromUid(callingUid)
.setLaunchedFromPackage(callingPackage) // com.android.launcher
.setLaunchedFromFeature(callingFeatureId) // null
.setIntent(intent)
.setResolvedType(resolvedType) // null
.setActivityInfo(aInfo)
.setConfiguration(mService.getGlobalConfiguration()) // 使用 global config
.setResultTo(resultRecord) // null
.setResultWho(resultWho) // null
.setRequestCode(requestCode) // -1
.setComponentSpecified(request.componentSpecified) // false
.setRootVoiceInteraction(voiceSession != null) // false
.setActivityOptions(checkedOptions) // 这个就是启动 Activity 传入的 Bundle 参数
.setSourceRecord(sourceRecord) // launcher
.build();
// mLastStartActivityRecord 保存最近一次启动的activity
mLastStartActivityRecord = r;
// ...
// 以 ActivityRecord 为参数,继续执行启动
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
request.voiceInteractor, startFlags, checkedOptions,
inTask, inTaskFragment, balCode, intentGrants, realCallingUid);
// ...
return mLastStartActivityResult;
}
如注释所说,这一步做了启动前的检查,然后创建 ActivityRecord,最后利用 ActivityRecord 来执行下一步的启动。
在这一步中,我还展示了 START u0 的 log 是如何构造的,这里展示下实际的 log
ActivityTaskManager: START u0
{act=com.android.intent.MAIN,
cat=[com.android.category.LAUNCHER],
flg=0x10200000, cmp=com.example.helloworld/.MainActivity ....} ...
result code = 0
大括号内是 Intent 的信息,flg 的值中包含 FLAG_ACTIVITY_NEW_TASK,所以从桌面冷启动 App,是需要新建一个 Task 的。
startActivityUnchecked()
// ActivityStarter.java
/**
* Start an activity while most of preliminary checks has been done and caller has been
* confirmed that holds necessary permissions to do so.
* Here also ensures that the starting activity is removed if the start wasn't successful.
*/
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment, @BalCode int balCode,
NeededUriGrants intentGrants, int realCallingUid) {
int result = START_CANCELED;
final Task startedActivityRootTask;
final TransitionController transitionController = r.mTransitionController;
// 1.创建 OPEN transition,并使 transition 进入收集状态
Transition newTransition = transitionController.isShellTransitionsEnabled()
? transitionController.createAndStartCollecting(TRANSIT_OPEN) : null;
// 从 launcher 启动 app 时,会携带一个 RemoteTranstion 数据,与桌面的远程动画相关
RemoteTransition remoteTransition = r.takeRemoteTransition();
try {
mService.deferWindowLayout();
// 1.1 transition 收集正在启动的 ActivityRecord
transitionController.collect(r);
try {
// 注意,这里有一个第一阶段的启动 trace
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
// 2. 继续启动 activity
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, options, inTask, inTaskFragment, balCode,
intentGrants, realCallingUid);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
// 3.处理启动结果
startedActivityRootTask = handleStartResult(r, options, result, newTransition,
remoteTransition);
}
} finally {
mService.continueWindowLayout();
}
// 注意这段代码中关于 START_TASK_TO_FRONT 和 START_DELIVERED_TO_TOP 结果的处理,与PIP等功能有关
postStartActivityProcessing(r, result, startedActivityRootTask);
return result;
}
这一步主要做了三件事
- 创建一个 OPEN Transition ,并收集 ActivityRecord。
- 执行下一步启动。
- 处理启动结果。如果启动成功,OPEN transition 会收集 ActivityRecord 的存在性改变,还会向 WMShell 请求 OPEN transition。
注意,本文不分析 transition 动画,只分析 Activity 生命周期如何执行的。
startActivityInner()
// ActivityStarter.java
/**
* Start an activity and determine if the activity should be adding to the top of an existing
* task or delivered new intent to an existing activity. Also manipulating the activity task
* onto requested or valid root-task/display.
*
* Note: This method should only be called from {@link #startActivityUnchecked}.
*/
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, ActivityOptions options, Task inTask,
TaskFragment inTaskFragment, @BalCode int balCode,
NeededUriGrants intentGrants, int realCallingUid) {
// 保存并解析一些初始状态,例如, mStartActivity 保存要启动的 Activity,mDoResume 解析为 true
setInitialState(r, options, inTask, inTaskFragment, startFlags, sourceRecord,
voiceSession, voiceInteractor, balCode, realCallingUid);
// ...
// app 冷启动,是需要新建 Task,所以这里是找不到可以直接使用的 Task
final boolean includeLaunchedFromBubble =
Flags.onlyReuseBubbledTaskWhenLaunchedFromBubble()
? sourceActivityLaunchedFromBubble : true;
final Task reusedTask = resolveReusableTask(includeLaunchedFromBubble);
// ...
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
// true
final boolean newTask = targetTask == null;
// null
mTargetTask = targetTask;
// ...
// null
final ActivityRecord targetTaskTop = newTask
? null : targetTask.getTopNonFinishingActivity();
if (targetTaskTop != null) {
// ...
} else {
// 需要把 ActivityRecord 添加到 Task
mAddingToTask = true;
}
// ...
if (mTargetRootTask == null) {
// 1. 创建 root task ,并且作为 top child 保存到 TaskDisplayArea 下
mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask,
mOptions);
}
if (newTask) {
// null
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
// 2. root task 作为 leaf task,把 ActivityRecord 作为 top child 保存
setNewTask(taskToAffiliate);
} else if (mAddingToTask) {
// ...
}
// ...
final Task startedTask = mStartActivity.getTask();
if (newTask) {
// 创建 task 的 event log : wm_create_task
EventLogTags.writeWmCreateTask(mStartActivity.mUserId, startedTask.mTaskId,
startedTask.getRootTaskId(), startedTask.getDisplayId());
}
// 启动 Activity 的 event log : wm_create_activity
mStartActivity.logStartActivity(EventLogTags.WM_CREATE_ACTIVITY, startedTask);
// ...
// isTaskSwitch 为 true
final boolean isTaskSwitch = startedTask != prevTopTask;
// 3. 创建启动窗口
mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,
mOptions, sourceRecord);
if (mDoResume) {
final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
if (!mTargetRootTask.isTopActivityFocusable()
|| (topTaskActivity != null && topTaskActivity.isTaskOverlay()
&& mStartActivity != topTaskActivity)) {
// ...
} else {
// mTargetRootTask 目前已经是 top focused task
if (!mAvoidMoveToFront && mTargetRootTask.isTopActivityFocusable()
&& !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) {
// ...
}
// 4. ActivityRecord 的窗口层级已经构建成功,现在由 RWC 来执行下一步启动
// mTransientLaunch 来自于 mOptions 的解析 KEY_TRANSIENT_LAUNCH,这里值为 false
// 如果它为 true,那么表示不用等到暂停后台 Tasks 之后,就可以立即 start activity
mRootWindowContainer.resumeFocusedTasksTopActivities(
mTargetRootTask, mStartActivity, mOptions, mTransientLaunch);
}
}
// ...
return START_SUCCESS;
}
首先介绍下窗口层级树,如下
graph TD
RootWindowContainer --> DisplayContent
DisplayContent --> DislayArea1
DisplayContent --> DislayArea
DisplayContent --> DislayArea2
DislayArea --> TaskDisplayArea
TaskDisplayArea --> Task
Task --> ActivityRecord
ActivityRecord --> WindowState
其中,RootWindowContainer 是层级树的根,DisplayContent 代表一个屏幕,DisplayArea 管理 DisplayContent 下某些层级的区域,TaskDisplayArea 是用来管理 Task,Task 用来保存代表 Activity 的 ActivityRecord,ActivityRecord 保存代表窗口的 WindowState。
这一步主要就是为了构建窗口层级,过程如下
- 创建 root Task,并以 top child 保存到 TaskDisplayArea 下。什么是 root Task ? 它的 parent 不是 Task,那么它就是 root task。
- root Task 作为 leaf Task,把 target ActivityRecord 作为 top child 进行保存。什么是 leaf Task ? 其实 Task 下面也可以保存子 Task,子 Task 下面如果没有 Task,那么子 Task 就是 leaf Task。
- 创建启动窗口。就是 App 开发经常说的 splash screen。
- 窗口层级构建完成后,通过层级树的根 RootWindowContainer 来执行下一步的 Activity 启动。
经过这一步之后,窗口层级树如下
graph TD
RootWindowContainer --> DisplayContent
DisplayContent --> DislayArea1
DisplayContent --> DislayArea
DisplayContent --> DislayArea2
DislayArea --> TaskDisplayArea
TaskDisplayArea --> Task
Task --> ActivityRecord
ActivityRecord --> WindowState
TaskDisplayArea --> targetTask
targetTask --> taretActivityRecord
其中,targetTask 是新建的 Task,targetActivityRecord 就是要启动的 Activity。
RootWindowContainer
// RootWindowContainer.java
// targetRootTask 就是要启动 activity 的 root task
// target 就是要启动的 activity
// targetOptions 是 start activity 的参数
// deferPause 为 false
boolean resumeFocusedTasksTopActivities(
Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions,
boolean deferPause) {
if (!mTaskSupervisor.readyToResume()) {
return false;
}
boolean result = false;
// targetRootTask 是作为 top child 保存在 TDA 下,因此它现在就是 top root task
if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea()
|| getTopDisplayFocusedRootTask() == targetRootTask)) {
// 由 toot task resume top activity
result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions,
deferPause);
}
// 处理 activity 启动失败的情况
// 例如,从桌面启动 activity 失败,至少系统得再把桌面拉起来
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
// ...
}
return result;
}
RootWindowContainer 交给 root task 来 resume top activity,这个 top activity 就是要启动的 Activity。
root Task#resumeTopActivityUncheckedLocked()
// 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.
*
*/
// 参数 prev 此时就是要启动的 activity,但是从命名以及注释来看,它的意思耐人寻味
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
// ...
boolean someActivityResumed = false;
try {
// Protect against recursion.
mInResumeTopActivity = true;
if (isLeafTask()) { // leaf Task
if (isFocusableAndVisible()) { // top activity 可以获焦,并且 task 处于 top,需要可见
// root task 作为 leaf Task 来 resume top activity
someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause);
}
} else {
// ... 这里处理不是 leaf task 的情况,不外乎就是遍历 children,然后递归调用当前方法
}
// ...
} finally {
mInResumeTopActivity = false;
}
return someActivityResumed;
}
root task 交给 leaf task 来 resume top activity,对于本案例来说,root task 就是 leaf task。
leaf Task#resumeTopActivityInnerLocked()
// Task.java
// prev 是要启动的 activity
// options 是启动 activity 的参数
// deferPause 为 false
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
if (!mAtmService.isBooting() && !mAtmService.isBooted()) {
// Not ready yet!
return false;
}
//获取 Task 的 top-focusable-non-finishing-activty
final ActivityRecord topActivity = topRunningActivity(true /* focusableOnly */);
if (topActivity == null) {
// ...
}
final boolean[] resumed = new boolean[1];
final TaskFragment topFragment = topActivity.getTaskFragment();
// 由 top activity 的 TaskFragment 来启动 top activity
resumed[0] = topFragment.resumeTopActivity(prev, options, deferPause);
// 看看其他 TaskFragment 是否能 resume top activity
forAllLeafTaskFragments(f -> {
// ...
}, true);
return resumed[0];
}
leaf task 交给 activity 的 TaskFragment 来 resume top activity。
Task 本身就是继承自 TaskFragment,对于本案例来说,leaf task 下是没有子 TaskFragment 的,因此 activity 的 TaskFragment 就是 leaf task ,也是 root task。
TaskFragment#resumeTopActivity()
// TaskFragment.java
// prev 就是要启动的 activity
// deferPause 为 false
final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
// 获取 top-focusable-non-finishing-activity,其实就是要启动的 activity
ActivityRecord next = topRunningActivity(true /* focusableOnly */);
// ...
// 如果当前有 Actvity 正在暂停,那么什么也不做
// If we are currently pausing an activity, then don't do anything until that is done.
final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
if (!allPausedComplete) {
ProtoLog.v(WM_DEBUG_STATES,
"resumeTopActivity: Skip resume: some activity pausing.");
return false;
}
final TaskDisplayArea taskDisplayArea = getDisplayArea();
// Task 才刚刚创建,mResumedActivity 和 mLastPausedActivity 都为 null
if (mResumedActivity == next && next.isState(RESUMED)
&& taskDisplayArea.allResumedActivitiesComplete()) {
// ....
return false;
}
if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
// ...
return false;
}
// ...
// 1.暂停后台 Task
// 此时 deferPause 为 false,表示不能推迟暂停后台 tasks
// 只要有一个后台 Task 正在暂停,那么返回 true
boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
if (mResumedActivity != null) {
// ...
}
if (pausing) {
ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivity: Skip resume: need to"
+ " start pausing");
if (next.attachedToProcess()) { // 此时还没有进程
// ...
} 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();
// 2. 由于有后台 Task 正在暂停,因此不能立即 start activity,但是可以先拉起进程
mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop,
isTop ? HostingRecord.HOSTING_TYPE_NEXT_TOP_ACTIVITY
: HostingRecord.HOSTING_TYPE_NEXT_ACTIVITY);
}
// 注意,这里就结束了
return true;
} else if (mResumedActivity == next && next.isState(RESUMED)
&& taskDisplayArea.allResumedActivitiesComplete()) {
// ...
}
// ...
}
本案例分析的是 app 冷启动,TaskFragment 先暂停了后台 Tasks,然后拉起 app 进程。
暂停后台 Tasks
所有的 Task 都由 TaskDisplayArea 管理,因此暂停后台 Tasks 的任务,当然是交给 TaskDisplayArea 来处理
对于本文分析的案例,此时需要暂停的后台 Tasks 只有 Launcher Task。
// TaskDisplayArea.java
boolean pauseBackTasks(ActivityRecord resuming) {
final int[] someActivityPaused = {0};
// 由 leaf task 来暂停 activity
forAllLeafTasks(leafTask -> {
if (leafTask.pauseActivityIfNeeded(resuming, "pauseBackTasks")) {
someActivityPaused[0]++;
}
}, true /* traverseTopToBottom */);
return someActivityPaused[0] > 0;
}
// Task.java
boolean pauseActivityIfNeeded(@Nullable ActivityRecord resuming, @NonNull String reason) {
if (!isLeafTask()) {
return false;
}
final int[] someActivityPaused = {0};
if (!isLeafTaskFragment()) {
}
forAllLeafTaskFragments((taskFrag) -> {
// 获取 resumed activity
final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
// 暂停后台 Task 的两个条件
if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
// 由 TaskFragment 来处理暂停
if (taskFrag.startPausing(false /* uiSleeping*/, resuming, reason)) {
someActivityPaused[0]++;
}
}
}, true /* traverseTopToBottom */);
return someActivityPaused[0] > 0;
}
TaskDisplayArea 把任务交给所有的 leaf task,leaf task 把任务交给所有的 leaf TaskFragment。
只有 TaskFragment 有 resumed activity,并且要启动的 activity 不属于这个 TaskFragment,这样就可以执行暂停 Task 的任务。
// TaskFragment.java
final boolean startPausing(boolean uiSleeping, ActivityRecord resuming, String reason) {
return startPausing(mTaskSupervisor.mUserLeaving, uiSleeping, resuming, reason);
}
// userLeaving 为 true
// uiSleeping 为 false
// resuming 就是要启动的 activity
// reason 为 pauseBackTasks
boolean startPausing(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming,
String reason) {
if (!hasDirectChildActivities()) {
return false;
}
ProtoLog.d(WM_DEBUG_STATES, "startPausing: taskFrag =%s " + "mResumedActivity=%s", this,
mResumedActivity);
if (mPausingActivity != null) {
}
ActivityRecord prev = mResumedActivity;
if (prev == null) {
}
if (prev == resuming) {
}
ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSING: %s", prev);
// 标记正在暂停的 activity
// 这个就是当前的 resumed activity
mPausingActivity = prev;
// TODO: 此时就标记已经暂停的 activity,是不是有点不妥?
mLastPausedActivity = prev;
if (!prev.finishing && prev.isNoHistory()
&& !mTaskSupervisor.mNoHistoryActivities.contains(prev)) {
}
// 1. 切换 PAUSING 状态,并且 TaskFragment 还会清空 mResumedActivity
prev.setState(PAUSING, "startPausingLocked");
// ...
boolean pauseImmediately = false;
boolean shouldAutoPip = false;
if (resuming != null) {
// ...
if (prev.supportsEnterPipOnTaskSwitch && userLeaving
&& resumingOccludesParent && lastResumedCanPip
&& prev.pictureInPictureArgs.isAutoEnterEnabled()) {
// ...
} else if (!lastResumedCanPip) {
// If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous
// activity to be paused.
// FLAG_RESUME_WHILE_PAUSING 表示不用等到 app 反馈暂停完成,服务端就可以立即完成暂停
// FLAG_RESUME_WHILE_PAUSING 来自于 AndroidMainfest 的 Activity 属性
pauseImmediately = (resuming.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
} else {
}
}
if (prev.attachedToProcess()) {
if (shouldAutoPip && ActivityTaskManagerService.isPip2ExperimentEnabled()) {
// ...
} else if (shouldAutoPip) {
// ...
} else {
// 2.通知 app 端暂停 activity
schedulePauseActivity(prev, userLeaving, pauseImmediately,
false /* autoEnteringPip */, reason);
}
} else {
// ...
}
// ...
// If already entered PIP mode, no need to keep pausing.
if (mPausingActivity != null) {
if (!uiSleeping) {
// 暂停事件分发
prev.pauseKeyDispatchingLocked();
} else {
// ...
}
// FLAG_RESUME_WHILE_PAUSING 就是在这里起作用的,服务端立即 complete pause,
// 而不用等到 app 反馈暂停完成。
// 本案例不走这里
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 {
// app 反馈暂停完成也有超时时间限制
prev.schedulePauseTimeout();
// All activities will be stopped when sleeping, don't need to wait for pause.
if (!uiSleeping) {
// 3.强制设置 transition ready 为 false
// Unset readiness since we now need to wait until this pause is complete.
mTransitionController.setReady(this, false /* ready */);
}
return true;
}
} else {
// ...
}
}
这里就是暂停后台 Task 的真正的逻辑
- 把 resumed activity 标记为 pausing activity,并切换状态为 PAUSING。与此同时,TaskFragment 会清理 resumed activity。
- 通知 app 端去 pause activity。
- 强制设置 transition ready 为 false,因为 pause activity 的生命周期流程还没有走完。
小结
第一阶段启动,主要做了如下事情
- 创建 ActivityRecord 和 Task,并构建窗口层级。
- 创建 OPEN Transition,收集了存在性改变的 ActivityRecord 和 Task。
- 暂停后台 Tasks,即通知 app 端去 pause Activity。
- 拉起 app 进程。
- 向 WMShell 发起 transition request。
第二阶段启动
app 端 pause activity 后,会通知服务端,服务端会再尝试启动 Activity,我称之为第二阶段启动
// ActivityClientController.java
public void activityPaused(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized (mGlobalLock) {
// 注意,这里有 activity paused 的 trace
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityPaused");
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r != null) {
// ActvityRecord 处理 activity paused
r.activityPaused(false);
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
Binder.restoreCallingIdentity(origId);
}
// ActivityRecord.java
void activityPaused(boolean timeout) {
ProtoLog.v(WM_DEBUG_STATES, "Activity paused: token=%s, timeout=%b", token,
timeout);
final TaskFragment taskFragment = getTaskFragment();
if (taskFragment != null) {
removePauseTimeout();
final ActivityRecord pausingActivity = taskFragment.getPausingActivity();
if (pausingActivity == this) {
ProtoLog.v(WM_DEBUG_STATES, "Moving to PAUSED: %s %s", this,
(timeout ? "(due to timeout)" : " (pause complete)"));
mAtmService.deferWindowLayout();
try {
// taskFragment 执行 complete pause
// 第一个参数 resumeNext 为 true,表示需要 resume top activity
taskFragment.completePause(true /* resumeNext */, null /* resumingActivity */);
} finally {
// 由于有可见性更新,因此 continue layout 会发起窗口刷新
mAtmService.continueWindowLayout();
}
return;
} else {
// ...
}
}
// ...
}
// TaskFragment.java
// resumeNext 为 true
// resuming 为 null
void completePause(boolean resumeNext, ActivityRecord resuming) {
ActivityRecord prev = mPausingActivity;
ProtoLog.v(WM_DEBUG_STATES, "Complete pause: %s", prev);
// 1. 完成 activity pause 流程
if (prev != null) {
prev.setWillCloseOrEnterPip(false);
// 当前状态为 PAUSING
final boolean wasStopping = prev.isState(STOPPING);
// 状态切换到 PAUSED
prev.setState(PAUSED, "completePausedLocked");
mPausingActivity = null;
if (prev.finishing) {
} else if (prev.attachedToProcess()) {
ProtoLog.v(WM_DEBUG_STATES, "Enqueue pending stop if needed: %s "
+ "wasStopping=%b visibleRequested=%b", prev, wasStopping,
prev.isVisibleRequested());
if (wasStopping) {
} else if (!prev.isVisibleRequested() || shouldSleepOrShutDownActivities()) {
}
} else {
}
if (prev != null) {
prev.stopFreezingScreen(true /* unfreezeNow */, true /* force */);
}
}
// 2. 由 RWC 继续启动 activity
if (resumeNext) {
final Task topRootTask = mRootWindowContainer.getTopDisplayFocusedRootTask();
if (topRootTask != null && !topRootTask.shouldSleepOrShutDownActivities()) {
// 由 RWC resume top activity of top root task
mRootWindowContainer.resumeFocusedTasksTopActivities(topRootTask, prev,
null /* targetOptions */);
} else {
}
}
if (prev != null) {
// 注意,activity 暂停完成后,才恢复事件分发
prev.resumeKeyDispatchingLocked();
}
// 3. 更新所有 activity 可见性
// resuming 为 null
mRootWindowContainer.ensureActivitiesVisible(resuming);
// ...
}
activity pause 流程,最终是由其 TaskFragment 处理
- 把 mPausingActivity 的状态切换到 PAUSED,并清理 mPausingActivity。
- 由 RootWindowContainer resume top activity of top root task,也就是继续启动 activity。
- 更新所有 Activity 的可见性。这里涉及到 stop activity 生命周期流程。
RootWindowContainer 启动 activity
RootWindowContainer 启动 activity 的方法,在前面已经分析过,最终是由 TaskFragment 来启动 activity。
// TaskFragment.java
// 参数 prev 此时代表已经完成暂停的 Activity
// options 为 null
// deferPause 为 false
final boolean resumeTopActivity(ActivityRecord prev, ActivityOptions options,
boolean deferPause) {
// 获取 top-focusable-non-finishing activity,就是要启动的 activity
ActivityRecord next = topRunningActivity(true /* focusableOnly */);
// ...
// 此时后台 Tasks 都已经暂停完成
final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
// 如果还有 Task 正在暂停,是不能启动 activity 的
if (!allPausedComplete) {
ProtoLog.v(WM_DEBUG_STATES,
"resumeTopActivity: Skip resume: some activity pausing.");
return false;
}
final TaskDisplayArea taskDisplayArea = getDisplayArea();
// 此时 mResumedActivity 为 null
if (mResumedActivity == next && next.isState(RESUMED)
&& taskDisplayArea.allResumedActivitiesComplete()) {
// ....
return false;
}
// 此时 mLastPausedActivity 为 null
if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
// ...
return false;
}
// ...
// 暂停后台 Task
// 此时已经没有需要暂停的后台 Task 了,因此这里返回 false
boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next);
// mResumedActivity 为 null
if (mResumedActivity != null) {
// ...
}
if (pausing) {
// ...
}
// mResumedActivity 为 null
else if (mResumedActivity == next && next.isState(RESUMED)
&& taskDisplayArea.allResumedActivitiesComplete()) {
// ....
return true;
}
// ...
// next 代表要启动的 activity
// next.nowVisible 代表是 Acivity 的窗口是否可见,现在是不可见的
if (prev != null && prev != next && next.nowVisible) {
// ...
}
// ...
boolean anim = true;
final DisplayContent dc = taskDisplayArea.mDisplayContent;
if (prev != null) {
if (prev.finishing) {
// ...
} else {
if (DEBUG_TRANSITION) {
Slog.v(TAG_TRANSITION, "Prepare open transition: prev=" + prev);
}
if (mTaskSupervisor.mNoAnimActivities.contains(next)) {
} else {
// app transition 已经废弃
dc.prepareAppTransition(TRANSIT_OPEN,
next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0);
}
}
} else {
// ...
}
if (anim) {
// transition 会保存 app 制定的动画的 options
next.applyOptionsAnimation();
} else {
}
mTaskSupervisor.mNoAnimActivities.clear();
if (next.attachedToProcess()) { // 此时,app 进程还在创建中
// ...
} else {
// Whoops, need to restart this activity!
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
}
ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Restarting %s", next);
// 根据进程状态启动 activity
mTaskSupervisor.startSpecificActivity(next, true, true);
}
return true;
}
此时,根据 ActivityRecord 是否绑定到进程,来决定如何启动 activity。但是须知,拉起 app 进程其实是“非常慢”的一个过程,它基本上都是在 activity paused 之后才完成的。
// ActivityTaskSupervisor.java
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
// 进程还没有起来呢
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
boolean knownToBeDead = false;
if (wpc != null && wpc.hasThread()) {
// ...
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
final boolean isTop = andResume && r.isTopRunningActivity();
// 继续拉起进程
mService.startProcessAsync(r, knownToBeDead, isTop,
isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY
: HostingRecord.HOSTING_TYPE_ACTIVITY);
}
很不幸,由于 app 进程还在启动中,第二阶段启动,让然无法真正启动 Activity。
更新 ActivityRecord 可见性
RootWindowContainer 会把更新 ActivityRecord 可见性的任务交给 Task,Task 交给 EnsureActivitiesVisibleHelper
// EnsureActivitiesVisibleHelper.java
// starting 为 null
// notifyClients 为 true
void process(@Nullable ActivityRecord starting, boolean notifyClients) {
reset(starting, notifyClients);
if (DEBUG_VISIBILITY) {
Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + mTopRunningActivity);
}
if (mTopRunningActivity != null && mTaskFragment.asTask() != null) {
mTaskFragment.asTask().checkTranslucentActivityWaiting(mTopRunningActivity);
}
// We should not resume activities that being launched behind because these
// activities are actually behind other fullscreen activities, but still required
// to be visible (such as performing Recents animation).
final boolean resumeTopActivity = mTopRunningActivity != null
&& !mTopRunningActivity.mLaunchTaskBehind
&& mTaskFragment.canBeResumed(starting)
&& (starting == null || !starting.isDescendantOf(mTaskFragment));
ArrayList<TaskFragment> adjacentTaskFragments = null;
for (int i = mTaskFragment.mChildren.size() - 1; i >= 0; --i) {
final WindowContainer child = mTaskFragment.mChildren.get(i);
final TaskFragment childTaskFragment = child.asTaskFragment();
if (childTaskFragment != null
&& childTaskFragment.getTopNonFinishingActivity() != null) {
// ..
} else if (child.asActivityRecord() != null) {
// 设置 activity 可见性
setActivityVisibilityState(child.asActivityRecord(), starting, resumeTopActivity);
}
}
}
EnsureActivitiesVisibleHelper 会针对 ActivityRecord ,设置可见性
// EnsureActivitiesVisibleHelper.java
private void setActivityVisibilityState(ActivityRecord r, ActivityRecord starting,
final boolean resumeTopActivity) {
// ...
if (reallyVisible) { // 一般来说,只有 top task 的 top activity 才需要可见
if (r.finishing) {
return;
}
if (DEBUG_VISIBILITY) {
Slog.v(TAG_VISIBILITY, "Make visible? " + r
+ " finishing=" + r.finishing + " state=" + r.getState());
}
// 当前要启动的 ActivityRecord 还处于 INITIALING 界面,因此这里不会更新可见性
if (r != mStarting && mNotifyClients) {
r.ensureActivityConfiguration(true /* ignoreVisibility */);
}
if (!r.attachedToProcess()) { // ActivityRecord 没有绑定到进程的情况
// 1. ActivityRecord设置可见,并且尝试启动 activity
makeVisibleAndRestartIfNeeded(mStarting, resumeTopActivity && isTop, r);
} else if (r.isVisibleRequested()) { // ActivityRecord 已经请求可见
} else { // ActivityRecord 绑定到进程,并且请求可见为 false
r.makeVisibleIfNeeded(mStarting, mNotifyClients);
}
} else { // 一般来说,top task 之下的 task 的 activity 都不可见
if (DEBUG_VISIBILITY) {
Slog.v(TAG_VISIBILITY, "Make invisible? " + r
+ " finishing=" + r.finishing + " state=" + r.getState()
+ " containerShouldBeVisible=" + mContainerShouldBeVisible
+ " behindFullyOccludedContainer=" + mBehindFullyOccludedContainer
+ " mLaunchTaskBehind=" + r.mLaunchTaskBehind);
}
// 2. 设置不可见
r.makeInvisible();
}
// ...
}
对于本案例来说,app task 现在已经是top task,而 Launcher task 是在其下。
那么,app task 的 ActivityRecord 的可见性,要被更新为 true,而 Launcher ActivityRecord 的可见性,要被更新为 false。
来看下 Launcher ActivityRecord 可见性更新为 false 的流程
// ActivityRecord.java
void makeInvisible() {
if (!mVisibleRequested) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this);
return;
}
// Now for any activities that aren't visible to the user, make sure they no longer are
// keeping the screen frozen.
if (DEBUG_VISIBILITY) {
Slog.v(TAG_VISIBILITY, "Making invisible: " + this + ", state=" + getState());
}
try {
final boolean canEnterPictureInPicture = checkEnterPictureInPictureState(
"makeInvisible", true /* beforeStopping */);
// Defer telling the client it is hidden if it can enter Pip and isn't current paused,
// stopped or stopping. This gives it a chance to enter Pip in onPause().
final boolean deferHidingClient = canEnterPictureInPicture
&& !isState(STARTED, STOPPING, STOPPED, PAUSED);
setDeferHidingClient(deferHidingClient);
// 1. 设置可见性为 false
setVisibility(false);
switch (getState()) {
case STOPPING:
case STOPPED:
// Reset the flag indicating that an app can enter picture-in-picture once the
// activity is hidden
supportsEnterPipOnTaskSwitch = false;
break;
case RESUMED:
case INITIALIZING:
case PAUSING:
case PAUSED:
case STARTED:
// 2. 进入 stopping 生命周期流程
addToStopping(true /* scheduleIdle */,
canEnterPictureInPicture /* idleDelayed */, "makeInvisible");
break;
default:
break;
}
} catch (Exception e) {
// Just skip on any failure; we'll make it visible when it next restarts.
Slog.w(TAG, "Exception thrown making hidden: " + intent.getComponent(), e);
}
}
本文只分析生命周期,因此第一步可见性更新就不分析了,看下第二步的进去 stop activity 流程
// ActivityRecord.java
// scheduleIdle 为 true
// idleDelayed 为 false
// reason 为 makeInvisible
void addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason) {
// 1. 加入到 mTaskSupervisor.mStoppingActivities 列表中
if (!mTaskSupervisor.mStoppingActivities.contains(this)) {
EventLogTags.writeWmAddToStopping(mUserId, System.identityHashCode(this),
shortComponentName, reason);
mTaskSupervisor.mStoppingActivities.add(this);
}
final Task rootTask = getRootTask();
boolean forceIdle = mTaskSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
|| (isRootOfTask() && rootTask.getChildCount() <= 1);
// scheduleIdle 此时为 true
if (scheduleIdle || forceIdle) {
ProtoLog.v(WM_DEBUG_STATES,
"Scheduling idle now: forceIdle=%b immediate=%b", forceIdle, !idleDelayed);
// idleDelayed 此时为 false
if (!idleDelayed) {
// 2.调度 idle
// 会执行 ActivityTaskSupervisor#activityIdleInterna()
mTaskSupervisor.scheduleIdle();
} else {
// ...
}
} else {
// ...
}
}
// ActivityTaskSupervisor.java
void activityIdleInternal(ActivityRecord r, boolean fromTimeout,
boolean processPausingActivities, Configuration config) {
if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + r);
if (r != null) {
// ...
}
// app task 还没有 resume activity 呢,那么 activity 肯定不是出于 idle 状态
if (mRootWindowContainer.allResumedActivitiesIdle()) {
// ...
}
// 处理 stopping 或者 finishing activity
processStoppingAndFinishingActivities(r, processPausingActivities, "idle");
if (DEBUG_IDLE) {
Slogf.i(TAG, "activityIdleInternal(): r=%s, mStartingUsers=%s", r, mStartingUsers);
}
// ...
}
// ActivityRecord.java
void processStoppingAndFinishingActivities(ActivityRecord launchedActivity,
boolean processPausingActivities, String reason) {
boolean displaySwapping = false;
// 处理 stopping activity
ArrayList<ActivityRecord> readyToStopActivities = null;
for (int i = 0; i < mStoppingActivities.size(); i++) {
final ActivityRecord s = mStoppingActivities.get(i);
// 是否处于 transition 动画
final boolean animating = s.isInTransition()
&& s.getTask() != null && !s.getTask().isForceHidden();
displaySwapping |= s.isDisplaySleepingAndSwapping();
ProtoLog.v(WM_DEBUG_STATES, "Stopping %s: nowVisible=%b animating=%b "
+ "finishing=%s", s, s.nowVisible, animating, s.finishing);
// 不处于 transition 动画,才可以把 ActivityRecord 从 mStoppingActivities 移除
// 并保存到 readyToStopActivities
if ((!animating && !displaySwapping) || mService.mShuttingDown
|| s.getRootTask().isForceHiddenForPinnedTask()) {
if (!processPausingActivities && s.isState(PAUSING)) {
}
ProtoLog.v(WM_DEBUG_STATES, "Ready to stop: %s", s);
if (readyToStopActivities == null) {
readyToStopActivities = new ArrayList<>();
}
readyToStopActivities.add(s);
mStoppingActivities.remove(i);
i--;
}
}
if (displaySwapping) {
}
// 让 readyToStopActivities 中的 Actvity 进入 stop 流程
final int numReadyStops = readyToStopActivities == null ? 0 : readyToStopActivities.size();
for (int i = 0; i < numReadyStops; i++) {
final ActivityRecord r = readyToStopActivities.get(i);
if (r.isInHistory()) {
if (r.finishing) {
} else {
// 通知 app stop activity
r.stopIfPossible();
}
}
}
// 省略处理 finishing activity 代码 ...
}
这里只是暂时 Launcher ActivityRecord 保存到 mTaskSupervisor.mStoppingActivities,而由于 Launcher ActivityRecord 此时处于 Transition 动画中,因此,无法执行 stop activity 流程。
从这里也可以推理出,当 Transition 动画结束时,才会执行 Launcher activity 的 stop 生命周期流程。
小结
第二阶段启动,始于 app 端通知服务端 activity paused 完成。但是,由于 app 进程还在启动中,因此仍然无法完成 activity 的启动。
但是,对于 Transition 动画来说,第二阶段启动还包含 ActivityRecord 可见性更新,其中 app ActivityRecord 可见性被更新为 true,Launcher ActivityRecord 的可见性被更新为 false。
第三阶段启动
当 app 进程起来后,它与服务端交互时,也会让服务端去启动 app 进程相关联的,并还未完成启动的 Activity。
由于 app 进程的启动,是一个异步过程,因此,我称之为第三阶段启动。
// ActivityThread.java
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// ...
Looper.prepareMainLooper();
// ...
// 创建 ActivityThread,并调用它的 attach()
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
// ...
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
private void attach(boolean system, long startSeq) {
// ..
if (!system) {
final IActivityManager mgr = ActivityManager.getService();
try {
// 1. attach app
// mAppThread 是一个 binder 回调,在服务端代表 app 进程
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// ...
} else {
// ...
}
// ...
}
ActivityThreaad#main() 最终就是向服务端注册一个 Binder 回调,这就是所谓的 attach app。
attach app
现在来看下服务端的 attach app 流程
// 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 (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
// 进程创建的时候,会保存到 mPidsSelfLocked
app = mPidsSelfLocked.get(pid);
}
if (app != null && (app.getStartUid() != callingUid || app.getStartSeq() != startSeq)) {
// ...
}
} else {
// ...
}
// ...
EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
// ...
try {
// ...
if (app.getIsolatedEntryPoint() != null) {
// ....
} else if (instr2 != null) {
// ...
} else {
// 1. 通知 app 进行 bind application
thread.bindApplication(processName, appInfo,
app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList, null, profilerInfo, null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new
// 来自 wps 的配置
Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap,
app.getStartElapsedTime(), app.getStartUptime());
}
// ...
synchronized (mProcLock) {
// 2. 进程与 app 端绑定
// 进程实例 ProcessRecord 保存 app 端传入的回调 IApplicationThread 对象
app.makeActive(thread, mProcessStats);
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
}
// ...
// mConstants.mEnableWaitForFinishAttachApplication 默认为 false
// 如果为 true,表示需要等待 app 完成 bind application 之后,才执行 finish attach application 操作
if (!mConstants.mEnableWaitForFinishAttachApplication) {
// 3. finish attach app
// 四大组件中如果有等待进程启动的,此时就可以启动组件
finishAttachApplicationInner(startSeq, callingUid, pid);
} else {
// ...
}
} catch (Exception e) {
// ...
}
}
服务端 attach app
- 通知 app 端 bind application,其实就是把数据发送给 app 端。
- 进程与 app 端绑定。
- finish attach app,主要是针对四大组件的启动。
finish attach app
// ActivityManagerService.java
private void finishAttachApplicationInner(long startSeq, int uid, int pid) {
final ProcessRecord app;
synchronized (mPidsSelfLocked) {
// 获取进程实例 ProcessRecord
app = mPidsSelfLocked.get(pid);
}
// ...
synchronized (this) {
// ...
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
// ...
}
}
// ...
}
}
// ActivityTaskManagerService.java
public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
synchronized (mGlobalLockWithoutBoost) {
// attach app 的 trace
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);
}
}
}
finish attach app 把启动 activity 的任务交给了 RootWindowContainer
// RootWindowContainer.java
boolean attachApplication(WindowProcessController app) throws RemoteException {
// 拉起app进程调用的 startProcessAsync() 中,会把要启动的 activity 保存到 mService.mStartingProcessActivities
final ArrayList<ActivityRecord> activities = mService.mStartingProcessActivities;
RemoteException remoteException = null;
boolean hasActivityStarted = false;
for (int i = activities.size() - 1; i >= 0; i--) {
final ActivityRecord r = activities.get(i);
// 省略检测是否要启动 activity 的代码 ...
try {
final boolean canResume = r.isFocusable() && r == tf.topRunningActivity();
// 真正启动 activity 来了
if (mTaskSupervisor.realStartActivityLocked(r, app, canResume,
true /* checkConfig */)) {
hasActivityStarted = true;
}
} catch (RemoteException e) {
Slog.w(TAG, "Exception in new process when starting " + r, e);
remoteException = e;
}
}
if (remoteException != null) {
throw remoteException;
}
return hasActivityStarted;
}
// ActivityTaskSupervisor.java
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
// 如果有 activity 还没有暂停完成,那么不能启动新 activity
if (!mRootWindowContainer.allPausedActivitiesComplete()) {
ProtoLog.v(WM_DEBUG_STATES,
"realStartActivityLocked: Skipping start of r=%s some activities pausing...",
r);
return false;
}
final Task task = r.getTask();
if (andResume) {
// 当前 task 没有 resumed activity,不需要 pause
if (task.pauseActivityIfNeeded(r, "realStart")) {
}
final TaskFragment taskFragment = r.getTaskFragment();
if (taskFragment != null && taskFragment.getResumedActivity() != null) {
}
}
final Task rootTask = task.getRootTask();
beginDeferResume();
proc.pauseConfigurationDispatch();// 推迟配置分发
try {
// ...
// ActivityRecord 先与进程绑定,再启动柜
r.setProcess(proc);
// ...
// checkConfig 此时为 true
if (checkConfig) {
// 更新 activity 可见性,以及确保 activity 能正确处理配置
// 可见性更新,在前面执行过
// 至于配置,ActivityRecord 还处于 INITIALING 状态,无需考虑
mRootWindowContainer.ensureVisibilityAndConfig(r, r.mDisplayContent,
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);
}
// ...
// 这个 binder 会发送给 app 端,app 端会利用它与服务端沟通 activity 状态
final IActivityClientController activityClientController =
proc.hasEverLaunchedActivity() ? null : mService.mActivityClientController;
r.launchCount++;
if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
// ...
try {
// ...
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
"Launching: " + r + " savedState=" + r.getSavedState()
+ " with results=" + results + " newIntents=" + newIntents
+ " andResume=" + andResume);
// 真正启动 activity 的 event log : wm_restart_activity
EventLogTags.writeWmRestartActivity(r.mUserId, System.identityHashCode(r),
task.mTaskId, r.shortComponentName);
// ...
// 有 WPC 的 full config 和 ActivityRecord 的 merged override config
// 共同组成发送给 app 的配置
final Configuration procConfig = proc.prepareConfigurationForLaunchingActivity();
final Configuration overrideConfig = r.getMergedOverrideConfiguration();
r.setLastReportedConfiguration(procConfig, overrideConfig);
// 这里会把 task bounds 也发送给 app 端
final ActivityWindowInfo activityWindowInfo = r.getActivityWindowInfo();
r.setLastReportedActivityWindowInfo(activityWindowInfo);
// ...
// Create activity launch transaction.
final boolean isTransitionForward = r.isTransitionForward();
final IBinder fragmentToken = r.getTaskFragment().getFragmentToken();
final int deviceId = getDeviceIdForDisplayId(r.getDisplayId());
// 创建 Launch activity callback
final LaunchActivityItem launchActivityItem = LaunchActivityItem.obtain(r.token,
r.intent, System.identityHashCode(r), r.info,
procConfig, overrideConfig, deviceId,
r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
results, newIntents, r.takeSceneTransitionInfo(), isTransitionForward,
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken,
r.initialCallerInfoAccessToken, activityWindowInfo);
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
// 创建 resume 生命周期请求
lifecycleItem = ResumeActivityItem.obtain(r.token, isTransitionForward,
r.shouldSendCompatFakeFocus());
} else if (r.isVisibleRequested()) {
} else {
}
// ...
// 通知 app 端启动 activity,并把生命周期执行到 resume
mService.getLifecycleManager().scheduleTransactionAndLifecycleItems(
proc.getThread(), launchActivityItem, lifecycleItem,
// Immediately dispatch the transaction, so that if it fails, the server can
// restart the process and retry now.
true /* shouldDispatchImmediately */);
// ...
} catch (RemoteException 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()) {
// 服务端执行一小部分的 resumed activity 流程
// 剩下的流程,是在 app 端通知 activity resumed 后执行
r.setState(RESUMED, "realStartActivityLocked");
r.completeResumeLocked();
} else if (r.isVisibleRequested()) {
} else {
}
// ...
return true;
}
ActivityTaskSupervisor#realStartActivityLocked() 正如函数名一样,真正用来启动 Activity, 其实就是通知 app 端启动 activity,并把生命周期执行到 resume。