system_server侧流程
代码路径:frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
java
public final int startActivityFromRecents(int taskId, Bundle bOptions) {
mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
"startActivityFromRecents()");
//获取
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
//封装options
final SafeActivityOptions safeOptions = SafeActivityOptions.fromBundle(bOptions);
final long origId = Binder.clearCallingIdentity();
try {
return mTaskSupervisor.startActivityFromRecents(callingPid, callingUid, taskId,
safeOptions);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
这里callingPid和callingUid为桌面pid 和uid,后续传递参数继续调用到ActivityTaskSupervisor.startActivityFromRecents。
代码路径:frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
java
/**
* Start the given task from the recent tasks. Do not hold WM global lock when calling this
* method to avoid potential deadlock or permission deny by UriGrantsManager when resolving
* activity (see {@link ActivityStarter.Request#resolveActivity} and
* {@link com.android.server.am.ContentProviderHelper#checkContentProviderUriPermission}).
*
* @return The result code of starter.
*/
int startActivityFromRecents(int callingPid, int callingUid, int taskId,
SafeActivityOptions options) {
final Task task;
final int taskCallingUid;
final String callingPackage;
final String callingFeatureId;
final Intent intent;
final int userId;
//获取传递过来的options
final ActivityOptions activityOptions = options != null
? options.getOptions(this)
: null;
boolean moveHomeTaskForward = true;
synchronized (mService.mGlobalLock) {
final boolean isCallerRecents = mRecentTasks.isCallerRecents(callingUid);
int activityType = ACTIVITY_TYPE_UNDEFINED;
if (activityOptions != null) {
activityType = activityOptions.getLaunchActivityType();
//这里主要就是判断是否要 冻结当前最近的任务列表顺序,直到用户与当前应用程序进行交互或发生超时。
if (activityOptions.freezeRecentTasksReordering() && (isCallerRecents
|| ActivityTaskManagerService.checkPermission(MANAGE_ACTIVITY_TASKS,
callingPid, callingUid) == PERMISSION_GRANTED)) {
mRecentTasks.setFreezeTaskListReordering();
}
//传递过来options中没有设置过mLaunchRootTask,因此getLaunchRootTask()的值为空
if (activityOptions.getLaunchRootTask() != null) {
// Don't move home activity forward if there is a launch root set.
moveHomeTaskForward = false;
}
}
//判断当前activity类型的合法性
if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
throw new IllegalArgumentException("startActivityFromRecents: Task "
+ taskId + " can't be launch in the home/recents root task.");
}
boolean shouldStartActivity = false;
//延迟窗口布局
mService.deferWindowLayout();
try {
//根据taskId获取Task对象
task = mRootWindowContainer.anyTaskForId(taskId,
MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
//task为空时,做窗口绘制处理并抛出异常
if (task == null) {
mWindowManager.executeAppTransition();
throw new IllegalArgumentException(
"startActivityFromRecents: Task " + taskId + " not found.");
}
if (moveHomeTaskForward) {
// We always want to return to the home activity instead of the recents
// activity from whatever is started from the recents activity, so move
// the home root task forward.
// TODO (b/115289124): Multi-display supports for recents.
//moveHomeRootTaskToFront会获取桌面rootTask,然后将其移至最前台
mRootWindowContainer.getDefaultTaskDisplayArea().moveHomeRootTaskToFront(
"startActivityFromRecents");
}
// If the user must confirm credentials (e.g. when first launching a work
// app and the Work Challenge is present) let startActivityInPackage handle
// the intercepting.
//android 13之前的的版本可能会进入该流程,
//本地使用的android 14,task.getRootActivity()为null,因此不进入此流程
if (!mService.mAmInternal.shouldConfirmCredentials(task.mUserId)
&& task.getRootActivity() != null) {
final ActivityRecord targetActivity = task.getTopNonFinishingActivity();
......
try {
//这里是把自由窗口的Task移到最顶部前端
mService.moveTaskToFrontLocked(null /* appThread */,
null /* callingPackage */, task.mTaskId, 0, options);
......
} finally {
mActivityMetricsLogger.notifyActivityLaunched(launchingState,
START_TASK_TO_FRONT, false /* newActivityCreated */,
targetActivity, activityOptions);
}
mService.getActivityStartController().postStartActivityProcessingForLastStarter(
task.getTopNonFinishingActivity(), ActivityManager.START_TASK_TO_FRONT,
task.getRootTask());
// As it doesn't go to ActivityStarter.executeRequest() path, we need to resume
// app switching here also.
mService.resumeAppSwitches();
return ActivityManager.START_TASK_TO_FRONT;
}
// The task is empty or needs to show the confirmation for credential.
shouldStartActivity = true;
} finally {
if (!shouldStartActivity) {
//继续窗口布局,与前面mService.deferWindowLayout()延迟窗口布局相呼应。
mService.continueWindowLayout();
}
}
......
}
// ActivityStarter will acquire the lock where the places need, so execute the request
// outside of the lock.
try {
// We need to temporarily disable the explicit intent filter matching enforcement
// because Task does not store the resolved type of the intent data, causing filter
// mismatch in certain cases. (b/240373119)
PackageManagerServiceUtils.DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.set(true);
//通过startActivityInPackage启动相应的Task中对应Activity并将其移至最前台,传递options、task等关键参数。
return mService.getActivityStartController().startActivityInPackage(taskCallingUid,
callingPid, callingUid, callingPackage, callingFeatureId, intent, null, null,
null, 0, 0, options, userId, task, "startActivityFromRecents",
false /* validateIncomingUser */, null /* originatingPendingIntent */,
BackgroundStartPrivileges.NONE);
} finally {
PackageManagerServiceUtils.DISABLE_ENFORCE_INTENTS_TO_MATCH_INTENT_FILTERS.set(false);
synchronized (mService.mGlobalLock) {
//继续窗口布局,与前面mService.deferWindowLayout()延迟窗口布局相呼应。
mService.continueWindowLayout();
}
}
}
startActivityFromRecents方法主要做了两件事:
- 使用
anyTaskForId方法,通过taskId找到对应的Task并设置其windowingMode。 - 通过
startActivityInPackage方法,启动Task中对应Activity并将其移至最前台。
通过taskId找到对应的Task并设置其windowingMode
java
task = mRootWindowContainer.anyTaskForId(taskId,
MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP);
这里主要传递应用taskId和activityOptions(携带需要设置的自由窗口相关参数)。
RootWindowContainer.anyTaskForId
代码路径:frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
java
/**
* Returns a {@link Task} for the input id if available. {@code null} otherwise.
*
* @param id Id of the task we would like returned.
* @param matchMode The mode to match the given task id in.
* @param aOptions The activity options to use for restoration. Can be null.
* @param onTop If the root task for the task should be the topmost on the display.
*/
Task anyTaskForId(int id, @RootWindowContainer.AnyTaskForIdMatchTaskMode int matchMode,
@Nullable ActivityOptions aOptions, boolean onTop) {
// If options are set, ensure that we are attempting to actually restore a task
if (matchMode != MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) {
throw new IllegalArgumentException("Should not specify activity options for non-restore"
+ " lookup");
}
//简单说就是创建了一个 task -> task.isTaskId(id) 的lamda表达式
final PooledPredicate p = PooledLambda.obtainPredicate(
Task::isTaskId, PooledLambda.__(Task.class), id);
//查找符合条件的task
Task task = getTask(p);
//将 PooledPredicate 对象回收到对象池中,以便重用,避免频繁的垃圾回收
p.recycle();
if (task != null) {
if (aOptions != null) {
// Resolve the root task the task should be placed in now based on options
// and reparent if needed.
// TODO(b/229927851) For split-screen, setLaunchRootTask is no longer the "root"
// task, consider to rename methods like "parentTask" instead of "rootTask".
//找到rootTask
final Task targetRootTask =
getOrCreateRootTask(null, aOptions, task, onTop);
// When launch with ActivityOptions#getLaunchRootTask, the "root task" just mean the
// parent of current launch, not the "root task" in hierarchy.
//这里是判断当前Task的获取到的rootTask与其task.getRootTask()的场景
//我们一般启动应用时情况如下:
//targetRootTask != null,true
//task.getRootTask() != targetRootTask,false
//task.getParent() != targetRootTask,false
//因此我们这里为false
//这个场景一般是task参数在特殊情况变null时,getOrCreateRootTask中会重新创建Task
if (targetRootTask != null && task.getRootTask() != targetRootTask
&& task.getParent() != targetRootTask) {
final int reparentMode = onTop
? REPARENT_MOVE_ROOT_TASK_TO_FRONT : REPARENT_LEAVE_ROOT_TASK_IN_PLACE;
task.reparent(targetRootTask, onTop, reparentMode, ANIMATE, DEFER_RESUME,
"anyTaskForId");
}
}
//返回获取到的task
return task;
}
//task为空的其他情况,省略
......
if (DEBUG_RECENTS) Slog.w(TAG_RECENTS, "Restored task id=" + id + " from in recents");
return task;
}
这个方法实际上就是通过getOrCreateRootTask做一些操作,然后返回给targetRootTask,做后续的条件判断处理。 在代码我们分析了后面的流程一般情况不会去走,因此暂不考虑。这里最后return 通过getTask(p)获取到的task。
这里我们重点分析下getOrCreateRootTask方法。
java
final Task targetRootTask =
getOrCreateRootTask(null, aOptions, task, onTop);
这里传递了从taskId中找到的对应task,以及前面创建options,其中参数null表示ActivityRecord为空。
RootWindowContainer.getOrCreateRootTask
java
/**
* Returns the right root task to use for launching factoring in all the input parameters.
*
* @param r The activity we are trying to launch. Can be null.
* @param options The activity options used to the launch. Can be null.
* @param candidateTask The possible task the activity might be launched in. Can be null.
* @param sourceTask The task requesting to start activity. Can be null.
* @param launchParams The resolved launch params to use.
* @param launchFlags The launch flags for this launch.
* @param realCallingPid The pid from {@link ActivityStarter#setRealCallingPid}
* @param realCallingUid The uid from {@link ActivityStarter#setRealCallingUid}
* @return The root task to use for the launch.
*/
Task getOrCreateRootTask(@Nullable ActivityRecord r,
@Nullable ActivityOptions options, @Nullable Task candidateTask,
@Nullable Task sourceTask, boolean onTop,
@Nullable LaunchParamsController.LaunchParams launchParams, int launchFlags) {
// First preference goes to the launch root task set in the activity options.
if (options != null) {
//这边传递过来的options没有设置过mLaunchRootTask
//因此options.getLaunchRootTask()为null,因此不进入此流程
final Task candidateRoot = Task.fromWindowContainerToken(options.getLaunchRootTask());
if (candidateRoot != null && canLaunchOnDisplay(r, candidateRoot)) {
return candidateRoot;
}
}
// Next preference goes to the task id set in the activity options.
if (options != null) {
//options.getLaunchRootTask()为null,因此不进入此流程
final int candidateTaskId = options.getLaunchTaskId();
if (candidateTaskId != INVALID_TASK_ID) {
......
}
}
// Next preference goes to the TaskDisplayArea candidate from launchParams
// or activity options.
TaskDisplayArea taskDisplayArea = null;
//launchParams传递过来的值为null
if (launchParams != null && launchParams.mPreferredTaskDisplayArea != null) {
taskDisplayArea = launchParams.mPreferredTaskDisplayArea;
} else if (options != null) {//options不为空,进入此流程给taskDisplayArea赋值
//当前的options中没有设置,因此options.getLaunchTaskDisplayArea()值为空
//即taskDisplayArea获取的值为null。
final WindowContainerToken daToken = options.getLaunchTaskDisplayArea();
taskDisplayArea = daToken != null
? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
if (taskDisplayArea == null) {
//options.getLaunchDisplayId()为null,因此不进入此流程
final int launchDisplayId = options.getLaunchDisplayId();
if (launchDisplayId != INVALID_DISPLAY) {
final DisplayContent displayContent = getDisplayContent(launchDisplayId);
if (displayContent != null) {
taskDisplayArea = displayContent.getDefaultTaskDisplayArea();
}
}
}
}
//获取activityType
//我们这里r即ActivityRecord为空,因此获取candidateTask的type
//即activityType为ACTIVITY_TYPE_STANDARD
final int activityType = resolveActivityType(r, options, candidateTask);
//此时taskDisplayArea仍然为空
if (taskDisplayArea != null) {
if (canLaunchOnDisplay(r, taskDisplayArea.getDisplayId())) {
return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask,
sourceTask, launchParams, launchFlags, activityType, onTop);
} else {
taskDisplayArea = null;
}
}
// Give preference to the root task and display of the input task and activity if they
// match the mode we want to launch into.
Task rootTask = null;
//传递过来的candidateTask不为空,因此获取其rootTask
if (candidateTask != null) {
rootTask = candidateTask.getRootTask();
}
//rootTask为空且ActivityRecord不为空的情况,通过ActivityRecord获取rootTask
if (rootTask == null && r != null) {
rootTask = r.getRootTask();
}
//launchParams为null,此时windowingMode为WINDOWING_MODE_UNDEFINED
int windowingMode = launchParams != null ? launchParams.mWindowingMode
: WindowConfiguration.WINDOWING_MODE_UNDEFINED;
if (rootTask != null) {
//获取rootTask对应的taskDisplayArea
taskDisplayArea = rootTask.getDisplayArea();
//此时taskDisplayArea不为null
//canLaunchOnDisplay中传递的r(ActivityRecord)和DisplayContent的DisplayId
//其中ActivityRecord为空,从canLaunchOnDisplay方法流程中可以得知该情况返回为true
if (taskDisplayArea != null
&& canLaunchOnDisplay(r, taskDisplayArea.mDisplayContent.mDisplayId)) {
//此时windowingMode为WINDOWING_MODE_UNDEFINED
if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
//该方法通过options.getLaunchWindowingMode()获取了自由窗口的windowingMode,其值为WINDOWING_MODE_FREEFORM
windowingMode = taskDisplayArea.resolveWindowingMode(r, options, candidateTask);
}
// Always allow organized tasks that created by organizer since the activity type
// of an organized task is decided by the activity type of its top child, which
// could be incompatible with the given windowing mode and activity type.
//rootTask.isCompatible(windowingMode, activityType),判断当前应用的windowingMode和activityType
//和新设置的windowingMode和activityType是否一致,一致则返回true,不一致则返回false
//简单来说这个方法就是判断windowingMode和activityType是否需要更新,如果需要更新就继续后面的流程。
//rootTask.mCreatedByOrganizer从代码上看涉及TaskFragment才会有true的情况
if (rootTask.isCompatible(windowingMode, activityType)
|| rootTask.mCreatedByOrganizer) {
//直接返回当前rootTask
return rootTask;
}
} else {
taskDisplayArea = null;
}
}
// Falling back to default task container
//taskDisplayArea为空时,直接获取默认的taskDisplayArea
if (taskDisplayArea == null) {
taskDisplayArea = getDefaultTaskDisplayArea();
}
//在taskDisplayArea中调用getOrCreateRootTask
return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask, sourceTask,
launchParams, launchFlags, activityType, onTop);
}
本次启动自由窗口时,rootTask = candidateTask.getRootTask();不为null,因此进入到rootTask != null的流程。 这里com.android.messaging进入自由窗口为例,使用dump命令adb shell dumpsys activity containers。
从dump中可以看到com.android.messaging的task为1226,在其之上没有别的task,因此rootTask实际上就是candidateTask它本身。
在rootTask.isCompatible(windowingMode, activityType) || rootTask.mCreatedByOrganizer条件中,返回的是false,因此不会直接返回rootTask。 这里我们主要先讲解下rootTask.isCompatible(windowingMode, activityType) 代码路径:frameworks/base/services/core/java/com/android/server/wm/Task.java
java
public boolean isCompatible(int windowingMode, int activityType) {
// TODO: Should we just move this to ConfigurationContainer?
if (activityType == ACTIVITY_TYPE_UNDEFINED) {
// Undefined activity types end up in a standard root task once the root task is
// created on a display, so they should be considered compatible.
activityType = ACTIVITY_TYPE_STANDARD;
}
return super.isCompatible(windowingMode, activityType);
}
判断activityType类型是否是ACTIVITY_TYPE_UNDEFINED,如果是则改为ACTIVITY_TYPE_STANDARD,之后调用其父类ConfigurationContainer.isCompatible方法 代码路径:frameworks/base/services/core/java/com/android/server/wm/ConfigurationContainer.java
java
/**
* Returns true if this container is compatible with the input windowing mode and activity type.
* The container is compatible:
* - If {@param activityType} and {@param windowingMode} match this container activity type and
* windowing mode.
* - If {@param activityType} is {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
* {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} and this containers activity type is also
* standard or undefined and its windowing mode matches {@param windowingMode}.
* - If {@param activityType} isn't {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} or
* {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} or this containers activity type isn't
* also standard or undefined and its activity type matches {@param activityType} regardless of
* if {@param windowingMode} matches the containers windowing mode.
*/
public boolean isCompatible(int windowingMode, int activityType) {
//获取当前activityType和windowingMode
final int thisActivityType = getActivityType();
final int thisWindowingMode = getWindowingMode();
//比较当前activityType和windowingMode和传递过来的activityType和windowingMode
final boolean sameActivityType = thisActivityType == activityType;
final boolean sameWindowingMode = thisWindowingMode == windowingMode;
//activityType和windowingMode均未发生变化
if (sameActivityType && sameWindowingMode) {
return true;
}
//activityType发生了变化
if ((activityType != ACTIVITY_TYPE_UNDEFINED && activityType != ACTIVITY_TYPE_STANDARD)
|| !isActivityTypeStandardOrUndefined()) {
// Only activity type need to match for non-standard activity types that are defined.
return sameActivityType;
}
// Otherwise we are compatible if the windowing mode is the same.
//windowingMode发生了变化
return sameWindowingMode;
}
通过getActivityType()和getWindowingMode()分别获取了当前activityType和windowingMode,然后进行变化,如果两者之一出现变化则返回false。
因此我们这里没有直接返回rootTask,而是调用到了taskDisplayArea.getOrCreateRootTask。
java
return taskDisplayArea.getOrCreateRootTask(r, options, candidateTask, sourceTask,
launchParams, launchFlags, activityType, onTop);
这里先回顾说明下传递的参数: r:ActivityRecord类型,其值由RootWindowContainer.anyTaskForId中传递过来,值为null。
options:ActivityOptions类型,其值从最初桌面侧FreeformSystemShortcut.startActivity调用startActivityFromRecents传递过来,包含来设置 窗口模式(mLaunchWindowingMode) 和 窗口大小(mLaunchBounds) 参数。
candidateTask:Task类型,其值由RootWindowContainer.anyTaskForId中传递过来,值为桌面侧传递过来taskId对应的Task。
sourceTask:Task类型,其值由RootWindowContainer.getOrCreateRootTask传递,值为null。
activityType:其值由RootWindowContainer.getOrCreateRootTask获取并传递,值为ACTIVITY_TYPE_STANDARD即1。
launchParams:LaunchParamsController.LaunchParams类型,其值由RootWindowContainer.getOrCreateRootTask传递,值为null。
launchFlags:int类型,其值由RootWindowContainer.getOrCreateRootTask传递,值为0。
onTop:boolean类型,其值由ActivityTaskSupervisor.startActivityFromRecents的anyTaskForId中传递过来,值为 ActivityTaskSupervisor.ON_TOP即true。
TaskDisplayArea.getOrCreateRootTask
代码路径:frameworks/base/services/core/java/com/android/server/wm/TaskDisplayArea.java
java
/**
* Returns an existing root task compatible with the input params or creates one
* if a compatible root task doesn't exist.
*
* @see #getOrCreateRootTask(int, int, boolean)
*/
Task getOrCreateRootTask(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
@Nullable Task candidateTask, @Nullable Task sourceTask,
@Nullable LaunchParams launchParams, int launchFlags, int activityType, boolean onTop) {
//设置windowingMode初始值为WINDOWING_MODE_UNDEFINED
int windowingMode = WINDOWING_MODE_UNDEFINED;
if (launchParams != null) {
// If launchParams isn't null, windowing mode is already resolved.
windowingMode = launchParams.mWindowingMode;
} else if (options != null) {
// If launchParams is null and options isn't let's use the windowing mode in the
// options.
//这里options不为空,options.getLaunchWindowingMode()值为WINDOWING_MODE_FREEFORM
windowingMode = options.getLaunchWindowingMode();
}
// Validate that our desired windowingMode will work under the current conditions.
// UNDEFINED windowing mode is a valid result and means that the new root task will inherit
// it's display's windowing mode.
//判断windowingMode有效性,并赋值
windowingMode = validateWindowingMode(windowingMode, r, candidateTask);
//继续传递参数
return getOrCreateRootTask(windowingMode, activityType, onTop, candidateTask, sourceTask,
options, launchFlags);
}
这里主要就是通过options.getLaunchWindowingMode()获取了windowingMode (WINDOWING_MODE_FREEFORM),在将其传递到getOrCreateRootTask方法中。
java
/**
* When two level tasks are required for given windowing mode and activity type, returns an
* existing compatible root task or creates a new one.
* For one level task, the candidate task would be reused to also be the root task or create
* a new root task if no candidate task.
*
* @param windowingMode The windowing mode the root task should be created in.
* @param activityType The activityType the root task should be created in.
* @param onTop If true the root task will be created at the top of the display,
* else at the bottom.
* @param candidateTask The possible task the activity might be launched in. Can be null.
* @param sourceTask The task requesting to start activity. Used to determine which of the
* adjacent roots should be launch root of the new task. Can be null.
* @param options The activity options used to the launch. Can be null.
* @param launchFlags The launch flags for this launch.
* @return The root task to use for the launch.
* @see #getRootTask(int, int)
*/
Task getOrCreateRootTask(int windowingMode, int activityType, boolean onTop,
@Nullable Task candidateTask, @Nullable Task sourceTask,
@Nullable ActivityOptions options, int launchFlags) {
//我们这里windowingMode传递的是WINDOWING_MODE_FREEFORM,
//因此resolvedWindowingMode为WINDOWING_MODE_FREEFORM
final int resolvedWindowingMode =
windowingMode == WINDOWING_MODE_UNDEFINED ? getWindowingMode() : windowingMode;
// Need to pass in a determined windowing mode to see if a new root task should be created,
// so use its parent's windowing mode if it is undefined.
//我们这里resolvedWindowingMode是WINDOWING_MODE_FREEFORM
//activityType是ACTIVITY_TYPE_STANDARD,因此alwaysCreateRootTask为true
//这取反为false,因此不进入该逻辑
if (!alwaysCreateRootTask(resolvedWindowingMode, activityType)) {
Task rootTask = getRootTask(resolvedWindowingMode, activityType);
if (rootTask != null) {
return rootTask;
}
} else if (candidateTask != null) {
final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
//这里getLaunchRootTask是同options获取,我们这里options没有设置过mLaunchRootTask,因此为null
final Task launchParentTask = getLaunchRootTask(resolvedWindowingMode, activityType,
options, sourceTask, launchFlags, candidateTask);
//launchParentTask为null不进入该流程
if (launchParentTask != null) {
if (candidateTask.getParent() == null) {
launchParentTask.addChild(candidateTask, position);
} else if (candidateTask.getParent() != launchParentTask) {
candidateTask.reparent(launchParentTask, position);
}
//candidateTask.getDisplayArea()和this都是默认的TaskDisplayArea,即DefaultTaskDisplayArea
//两者相同,即candidateTask.getDisplayArea() != this 为false,因此不进入该流程
} else if (candidateTask.getDisplayArea() != this
|| candidateTask.getRootTask().mReparentLeafTaskIfRelaunch) {
if (candidateTask.getParent() == null) {
addChild(candidateTask, position);
} else {
candidateTask.reparent(this, onTop);
}
}
// Update windowing mode if necessary, e.g. launch into a different windowing mode.
//windowingMode传递的是WINDOWING_MODE_FREEFORM
//candidateTask自身就是rootTask
//candidateTask前后windowingMode有发生变化
if (windowingMode != WINDOWING_MODE_UNDEFINED && candidateTask.isRootTask()
&& candidateTask.getWindowingMode() != windowingMode) {
//ShellTransitions调用collect处理
candidateTask.mTransitionController.collect(candidateTask);
//设置task窗口模式
candidateTask.setWindowingMode(windowingMode);
}
//返回candidateTask的rootTask
return candidateTask.getRootTask();
}
return new Task.Builder(mAtmService)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
.setOnTop(onTop)
.setParent(this)
.setSourceTask(sourceTask)
.setActivityOptions(options)
.setLaunchFlags(launchFlags)
.build();
}
这里我们重点看这一段
java
if (windowingMode != WINDOWING_MODE_UNDEFINED && candidateTask.isRootTask()
&& candidateTask.getWindowingMode() != windowingMode) {
candidateTask.mTransitionController.collect(candidateTask);
candidateTask.setWindowingMode(windowingMode);
}
return candidateTask.getRootTask();
先解析下这个条件
-
windowingMode != WINDOWING_MODE_UNDEFINEDwindowingMode传递的是WINDOWING_MODE_FREEFORM,因此该条件为true。 -
candidateTask.isRootTask()判断candidateTask是否是rootTask,关于这点前面有讲到,当前candidateTask就是rootTask,因此该条件为true。 -
candidateTask.getWindowingMode() != windowingMode)获取当前candidateTask的windowingMode,判断该windowingMode和传递过来的windowingMode是否一致,我们这里还没有启动到自由窗口,因此candidateTask.getWindowingMode()不是WINDOWING_MODE_FREEFORM,所以不一致,即该条件为true。
综上,所有条件都满足,所有进入该条件。 其中candidateTask.mTransitionController.collect(candidateTask);涉及ShellTransitions,这里不涉及,暂不讲解。
最终通过candidateTask.setWindowingMode(windowingMode)方法给candidateTask的windowingMode设置成了WINDOWING_MODE_FREEFORM。
总结
从mRootWindowContainer.anyTaskForId开始到TaskDisplayArea.getOrCreateRootTask结束,简单概括为一句话就是通过taskId获取对应task并设置该task的windowingMode为WINDOWING_MODE_FREEFORM(自由窗口)。
启动Task中对应Activity并将其移至最前台
java
return mService.getActivityStartController().startActivityInPackage(taskCallingUid,
callingPid, callingUid, callingPackage, callingFeatureId, intent, null, null,
null, 0, 0, options, userId, task, "startActivityFromRecents",
false /* validateIncomingUser */, null /* originatingPendingIntent */,
BackgroundStartPrivileges.NONE);