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

这里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方法主要做了两件事:

  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_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_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);
相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼5 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone5 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen5 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone5 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui