Android U 自由窗口(浮窗)——启动流程(system_server侧流程)

juejin.cn/editor/draf...

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);
        }
    }

这里callingPidcallingUid为桌面piduid,后续传递参数继续调用到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方法主要做了两件事:

  1. 使用anyTaskForId方法,通过taskId找到对应的Task并设置其windowingMode。
  2. 通过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_STANDARD1

launchParams:LaunchParamsController.LaunchParams类型,其值由RootWindowContainer.getOrCreateRootTask传递,值为null

launchFlags:int类型,其值由RootWindowContainer.getOrCreateRootTask传递,值为0

onTop:boolean类型,其值由ActivityTaskSupervisor.startActivityFromRecents的anyTaskForId中传递过来,值为 ActivityTaskSupervisor.ON_TOPtrue

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_UNDEFINED windowingMode传递的是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);
相关推荐
清空mega4 小时前
第11章 网络编程
android·网络
自动化BUG制造器4 小时前
Android UI 线程不一定是主线程
android
无知的前端4 小时前
一文读懂-Jetpack与AndroidX
android·kotlin·android jetpack
河铃旅鹿6 小时前
Android开发-java版:SQLite数据库
android·数据库·笔记·学习·sqlite
旋律逍遥6 小时前
《Framework 开发》3、开发工具及命令行知识装备
android
啦啦9117146 小时前
安卓手机/平板/TV版 Rotation强制横屏显示工具!免ROOT可用!再推荐突破手机限制的3款神器
android·智能手机·电脑
汤面不加鱼丸7 小时前
flutter实践:混合app在部分android旧机型上显示异常
android·flutter
_李小白8 小时前
【Android FrameWork】延伸阅读:ActivityManagerService启动Activity
android
用户41659673693558 小时前
Android 媒体库高效扫描器:基于协程与 `ContentObserver` 的 `FileScanner`
android