Android U 多任务启动分屏——system_server流程(更新中)

ops/2024/12/26 8:25:58/

前文

Android U 多任务启动分屏——SystemUI流程
前文说到Transitions的startTransition方法中,通过mOrganizer.startNewTransition(type, wct);提交WindowContainerTransaction相关事务到system_server侧,继续跟踪其流程。

system_server侧分屏处理流程

systemui跨进程通信到system_server

代码路径:frameworks/base/core/java/android/window/WindowOrganizer.java

    /*** Starts a new transition, don't use this to start an already created one.* @param type The type of the transition. This is ignored if a transitionToken is provided.* @param t The set of window operations that are part of this transition.* @return A token identifying the transition. This will be the same as transitionToken if it*         was provided.* @hide*/@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)@NonNullpublic IBinder startNewTransition(int type, @Nullable WindowContainerTransaction t) {try {return getWindowOrganizerController().startNewTransition(type, t);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}static IWindowOrganizerController getWindowOrganizerController() {return IWindowOrganizerControllerSingleton.get();}

这里可以看出getWindowOrganizerController()就是获取IWindowOrganizerController对象,调用其startNewTransition(type, t)方法,其中参数type为systemui侧传递的TRANSIT_TO_FRONT(值为3),t则是systemui侧传递的WindowContainerTransaction对象。

代码路径:frameworks/base/core/java/android/window/IWindowOrganizerController.aidl

interface IWindowOrganizerController {....../*** Starts a new transition.* @param type The transition type.* @param t Operations that are part of the transition.* @return a token representing the transition.*/IBinder startNewTransition(int type, in @nullable WindowContainerTransaction t);

找到其aidl接口,接下来找到其实现类

/*** Server side implementation for the interface for organizing windows* @see android.window.WindowOrganizer*/
class WindowOrganizerController extends IWindowOrganizerController.Stubimplements BLASTSyncEngine.TransactionReadyListener {

代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowOrganizerController.java

    @Overridepublic IBinder startNewTransition(int type, @Nullable WindowContainerTransaction t) {return startTransition(type, null /* transitionToken */, t);}

最终调用到WindowOrganizerController的startNewTransition方法,该方法就是调用一个startTransition方法,这个方法中传递了type(值为3)、transitionToken(值为null)以及WindowContainerTransaction对象。

处理动画并提交事务

    private IBinder startTransition(@WindowManager.TransitionType int type,@Nullable IBinder transitionToken, @Nullable WindowContainerTransaction t) {//检查MANAGE_ACTIVITY_TASKS权限enforceTaskPermission("startTransition()");final CallerInfo caller = new CallerInfo();final long ident = Binder.clearCallingIdentity();try {synchronized (mGlobalLock) {Transition transition = Transition.fromBinder(transitionToken);if (mTransitionController.getTransitionPlayer() == null && transition == null) {Slog.w(TAG, "Using shell transitions API for legacy transitions.");if (t == null) {throw new IllegalArgumentException("Can't use legacy transitions in"+ " compatibility mode with no WCT.");}applyTransaction(t, -1 /* syncId */, null, caller);return null;}final WindowContainerTransaction wct =t != null ? t : new WindowContainerTransaction();if (transition == null) {if (type < 0) {throw new IllegalArgumentException("Can't create transition with no type");}// This is a direct call from shell, so the entire transition lifecycle is// contained in the provided transaction if provided. Thus, we can setReady// immediately after apply.final boolean needsSetReady = t != null;final Transition nextTransition = new Transition(type, 0 /* flags */,mTransitionController, mService.mWindowManager.mSyncEngine);nextTransition.calcParallelCollectType(wct);mTransitionController.startCollectOrQueue(nextTransition,(deferred) -> {nextTransition.start();nextTransition.mLogger.mStartWCT = wct;applyTransaction(wct, -1 /* syncId */, nextTransition, caller,deferred);if (needsSetReady) {nextTransition.setAllReady();}});return nextTransition.getToken();}// The transition already started collecting before sending a request to shell,// so just start here.if (!transition.isCollecting() && !transition.isForcePlaying()) {Slog.e(TAG, "Trying to start a transition that isn't collecting. This probably"+ " means Shell took too long to respond to a request. WM State may be"+ " incorrect now, please file a bug");applyTransaction(wct, -1 /*syncId*/, null /*transition*/, caller);return transition.getToken();}transition.start();transition.mLogger.mStartWCT = wct;applyTransaction(wct, -1 /*syncId*/, transition, caller);// Since the transition is already provided, it means WMCore is determining the// "readiness lifecycle" outside the provided transaction, so don't set ready here.return transition.getToken();}} finally {Binder.restoreCallingIdentity(ident);}}
    private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId,@Nullable Transition transition, @NonNull CallerInfo caller, boolean deferred) {if (deferred) {try {return applyTransaction(t, syncId, transition, caller);} catch (RuntimeException e) {// If the transaction is deferred, the caller could be from TransitionController// #tryStartCollectFromQueue that executes on system's worker thread rather than// binder thread. And the operation in the WCT may be outdated that violates the// current state. So catch the exception to avoid crashing the system.Slog.e(TAG, "Failed to execute deferred applyTransaction", e);}return TRANSACT_EFFECTS_NONE;}return applyTransaction(t, syncId, transition, caller);}
    private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId,@Nullable Transition transition, @NonNull CallerInfo caller) {return applyTransaction(t, syncId, transition, caller, null /* finishTransition */);}

处理事务

    /*** @param syncId If non-null, this will be a sync-transaction.* @param transition A transition to collect changes into.* @param caller Info about the calling process.* @param finishTransition The transition that is currently being finished.* @return The effects of the window container transaction.*/private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId,@Nullable Transition transition, @NonNull CallerInfo caller,@Nullable Transition finishTransition) {int effects = TRANSACT_EFFECTS_NONE;ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);mService.deferWindowLayout();mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);try {if (transition != null) {transition.applyDisplayChangeIfNeeded();}final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();final int hopSize = hops.size();final ArraySet<WindowContainer<?>> haveConfigChanges = new ArraySet<>();Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =t.getChanges().entrySet().iterator();while (entries.hasNext()) {final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next();final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());if (wc == null || !wc.isAttached()) {Slog.e(TAG, "Attempt to operate on detached container: " + wc);continue;}// Make sure we add to the syncSet before performing// operations so we don't end up splitting effects between the WM// pending transaction and the BLASTSync transaction.if (syncId >= 0) {addToSyncSet(syncId, wc);}if (transition != null) transition.collect(wc);if ((entry.getValue().getChangeMask()& WindowContainerTransaction.Change.CHANGE_FORCE_NO_PIP) != 0) {// Disable entering pip (eg. when recents pretends to finish itself)if (finishTransition != null) {finishTransition.setCanPipOnFinish(false /* canPipOnFinish */);} else if (transition != null) {transition.setCanPipOnFinish(false /* canPipOnFinish */);}}// A bit hacky, but we need to detect "remove PiP" so that we can "wrap" the// setWindowingMode call in force-hidden.boolean forceHiddenForPip = false;if (wc.asTask() != null && wc.inPinnedWindowingMode()&& entry.getValue().getWindowingMode() == WINDOWING_MODE_UNDEFINED) {// We are in pip and going to undefined. Now search hierarchy ops to determine// whether we are removing pip or expanding pip.for (int i = 0; i < hopSize; ++i) {final WindowContainerTransaction.HierarchyOp hop = hops.get(i);if (hop.getType() != HIERARCHY_OP_TYPE_REORDER) continue;final WindowContainer hopWc = WindowContainer.fromBinder(hop.getContainer());if (!wc.equals(hopWc)) continue;forceHiddenForPip = !hop.getToTop();}}if (forceHiddenForPip) {wc.asTask().setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);// When removing pip, make sure that onStop is sent to the app ahead of// onPictureInPictureModeChanged.// See also PinnedStackTests#testStopBeforeMultiWindowCallbacksOnDismisswc.asTask().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);wc.asTask().mTaskSupervisor.processStoppingAndFinishingActivities(null /* launchedActivity */, false /* processPausingActivities */,"force-stop-on-removing-pip");}int containerEffect = applyWindowContainerChange(wc, entry.getValue(),t.getErrorCallbackToken());effects |= containerEffect;if (forceHiddenForPip) {wc.asTask().setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */);}// Lifecycle changes will trigger ensureConfig for everything.if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0&& (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {haveConfigChanges.add(wc);}}// Hierarchy changesif (hopSize > 0) {final boolean isInLockTaskMode = mService.isInLockTaskMode();for (int i = 0; i < hopSize; ++i) {effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,isInLockTaskMode, caller, t.getErrorCallbackToken(),t.getTaskFragmentOrganizer(), finishTransition);}}// Queue-up bounds-change transactions for tasks which are now organized. Do// this after hierarchy ops so we have the final organized state.entries = t.getChanges().entrySet().iterator();while (entries.hasNext()) {final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next();final WindowContainer wc = WindowContainer.fromBinder(entry.getKey());if (wc == null || !wc.isAttached()) {Slog.e(TAG, "Attempt to operate on detached container: " + wc);continue;}final Task task = wc.asTask();final Rect surfaceBounds = entry.getValue().getBoundsChangeSurfaceBounds();if (task == null || !task.isAttached() || surfaceBounds == null) {continue;}if (!task.isOrganized()) {final Task parent = task.getParent() != null ? task.getParent().asTask() : null;// Also allow direct children of created-by-organizer tasks to be// controlled. In the future, these will become organized anyways.if (parent == null || !parent.mCreatedByOrganizer) {throw new IllegalArgumentException("Can't manipulate non-organized task surface " + task);}}final SurfaceControl.Transaction sft = new SurfaceControl.Transaction();final SurfaceControl sc = task.getSurfaceControl();sft.setPosition(sc, surfaceBounds.left, surfaceBounds.top);if (surfaceBounds.isEmpty()) {sft.setWindowCrop(sc, null);} else {sft.setWindowCrop(sc, surfaceBounds.width(), surfaceBounds.height());}task.setMainWindowSizeChangeTransaction(sft);}if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);// Already calls ensureActivityConfigmService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);mService.mRootWindowContainer.resumeFocusedTasksTopActivities();} else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {for (int i = haveConfigChanges.size() - 1; i >= 0; --i) {haveConfigChanges.valueAt(i).forAllActivities(r -> {r.ensureActivityConfiguration(0, PRESERVE_WINDOWS);});}}if (effects != 0) {mService.mWindowManager.mWindowPlacerLocked.requestTraversal();}} finally {mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);mService.continueWindowLayout();}return effects;}

Task事务处理

接WindowOrganizerController.java中
private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId, @Nullable Transition transition, @NonNull CallerInfo caller, @Nullable Transition finishTransition)

Task区域大小bounds变化处理

int containerEffect = applyWindowContainerChange(wc, entry.getValue(),t.getErrorCallbackToken());

Task相关操作处理

该方法中applyHierarchyOp方法对象task操作进行相关处理

effects |= applyHierarchyOp(hops.get(i), effects, syncId, transition,isInLockTaskMode, caller, t.getErrorCallbackToken(),t.getTaskFragmentOrganizer(), finishTransition);

applyHierarchyOp方法中对task有很多种不同的操作,这里我们主要来看Task的启动、移除、重排序和重定向。
下面结合WindowContainerTransaction侧的构建的层级结构和applyHierarchyOp侧的实现来说明。

启动Task

WindowContainerTransaction

代码路径:frameworks/base/core/java/android/window/WindowContainerTransaction.java

    /*** Starts a task by id. The task is expected to already exist (eg. as a recent task).* @param taskId Id of task to start.* @param options bundle containing ActivityOptions for the task's top activity.* @hide*/@NonNullpublic WindowContainerTransaction startTask(int taskId, @Nullable Bundle options) {mHierarchyOps.add(HierarchyOp.createForTaskLaunch(taskId, options));return this;}/*** Holds information about a reparent/reorder operation in the hierarchy. This is separate from* Changes because they must be executed in the same order that they are added.* @hide*/public static final class HierarchyOp implements Parcelable {    	....../** Create a hierarchy op for launching a task. */public static HierarchyOp createForTaskLaunch(int taskId, @Nullable Bundle options) {final Bundle fullOptions = options == null ? new Bundle() : options;fullOptions.putInt(LAUNCH_KEY_TASK_ID, taskId);return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_LAUNCH_TASK).setToTop(true).setLaunchOptions(fullOptions).build();}
applyHierarchyOp

代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowOrganizerController.java

    private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,int syncId, @Nullable Transition transition, boolean isInLockTaskMode,@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,@Nullable ITaskFragmentOrganizer organizer, @Nullable Transition finishTransition) {final int type = hop.getType();switch (type) {......case HIERARCHY_OP_TYPE_LAUNCH_TASK: {mService.mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,"launchTask HierarchyOp");final Bundle launchOpts = hop.getLaunchOptions();final int taskId = launchOpts.getInt(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);final SafeActivityOptions safeOptions =SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents(caller.mPid, caller.mUid, taskId, safeOptions));break;}......}return effects;}

移除Task

WindowContainerTransaction

代码路径:frameworks/base/core/java/android/window/WindowContainerTransaction.java

    /*** Finds and removes a task and its children using its container token. The task is removed* from recents.* @param containerToken ContainerToken of Task to be removed*/@NonNullpublic WindowContainerTransaction removeTask(@NonNull WindowContainerToken containerToken) {mHierarchyOps.add(HierarchyOp.createForRemoveTask(containerToken.asBinder()));return this;}/*** Holds information about a reparent/reorder operation in the hierarchy. This is separate from* Changes because they must be executed in the same order that they are added.* @hide*/public static final class HierarchyOp implements Parcelable {....../** create a hierarchy op for deleting a task **/public static HierarchyOp createForRemoveTask(@NonNull IBinder container) {return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REMOVE_TASK).setContainer(container).build();}
applyHierarchyOp

代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowOrganizerController.java

    private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,int syncId, @Nullable Transition transition, boolean isInLockTaskMode,@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,@Nullable ITaskFragmentOrganizer organizer, @Nullable Transition finishTransition) {final int type = hop.getType();switch (type) {case HIERARCHY_OP_TYPE_REMOVE_TASK: {final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());if (wc == null || wc.asTask() == null || !wc.isAttached()) {Slog.e(TAG, "Attempt to remove invalid task: " + wc);break;}final Task task = wc.asTask();task.remove(true, "Applying remove task Hierarchy Op");break;}......}return effects;}

Task重定向和重排序

WindowContainerTransaction

代码路径:frameworks/base/core/java/android/window/WindowContainerTransaction.java

    /*** Reparents a container into another one. The effect of a {@code null} parent can vary. For* example, reparenting a stack to {@code null} will reparent it to its display.** @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to*              the bottom.*/@NonNullpublic WindowContainerTransaction reparent(@NonNull WindowContainerToken child,@Nullable WindowContainerToken parent, boolean onTop) {mHierarchyOps.add(HierarchyOp.createForReparent(child.asBinder(),parent == null ? null : parent.asBinder(),onTop));return this;}/*** Reorders a container within its parent.** @param onTop When {@code true}, the child goes to the top of parent; otherwise it goes to*              the bottom.*/@NonNullpublic WindowContainerTransaction reorder(@NonNull WindowContainerToken child, boolean onTop) {mHierarchyOps.add(HierarchyOp.createForReorder(child.asBinder(), onTop));return this;}/*** Holds information about a reparent/reorder operation in the hierarchy. This is separate from* Changes because they must be executed in the same order that they are added.* @hide*/public static final class HierarchyOp implements Parcelable {......public static HierarchyOp createForReparent(@NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT).setContainer(container).setReparentContainer(reparent).setToTop(toTop).build();}public static HierarchyOp createForReorder(@NonNull IBinder container, boolean toTop) {return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REORDER).setContainer(container).setReparentContainer(container).setToTop(toTop).build();}
applyHierarchyOp

代码路径:frameworks/base/services/core/java/com/android/server/wm/WindowOrganizerController.java

    private int applyHierarchyOp(WindowContainerTransaction.HierarchyOp hop, int effects,int syncId, @Nullable Transition transition, boolean isInLockTaskMode,@NonNull CallerInfo caller, @Nullable IBinder errorCallbackToken,@Nullable ITaskFragmentOrganizer organizer, @Nullable Transition finishTransition) {final int type = hop.getType();switch (type) {......case HIERARCHY_OP_TYPE_REORDER:case HIERARCHY_OP_TYPE_REPARENT: {final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());if (wc == null || !wc.isAttached()) {Slog.e(TAG, "Attempt to operate on detached container: " + wc);break;}// There is no use case to ask the reparent operation in lock-task mode now, so keep// skipping this operation as usual.if (isInLockTaskMode && type == HIERARCHY_OP_TYPE_REPARENT) {Slog.w(TAG, "Skip applying hierarchy operation " + hop+ " while in lock task mode");break;}if (isLockTaskModeViolation(wc.getParent(), wc.asTask(), isInLockTaskMode)) {break;}if (syncId >= 0) {addToSyncSet(syncId, wc);}if (transition != null) {transition.collect(wc);if (hop.isReparent()) {if (wc.getParent() != null) {// Collect the current parent. It's visibility may change as// a result of this reparenting.transition.collect(wc.getParent());}if (hop.getNewParent() != null) {final WindowContainer parentWc =WindowContainer.fromBinder(hop.getNewParent());if (parentWc == null) {Slog.e(TAG, "Can't resolve parent window from token");break;}transition.collect(parentWc);}}}effects |= sanitizeAndApplyHierarchyOp(wc, hop);break;}......}return effects;}

http://www.ppmy.cn/ops/145070.html

相关文章

R基于贝叶斯加法回归树BART、MCMC的DLNM分布滞后非线性模型分析母婴PM2.5暴露与出生体重数据及GAM模型对比、关键窗口识别

全文链接&#xff1a;https://tecdat.cn/?p38667 摘要&#xff1a;在母婴暴露于空气污染对儿童健康影响的研究中&#xff0c;常需对孕期暴露情况与健康结果进行回归分析。分布滞后非线性模型&#xff08;DLNM&#xff09;是一种常用于估计暴露 - 时间 - 响应函数的统计方法&am…

软件测试之压力测试【详解】

压力测试 压力测试是一种软件测试&#xff0c;用于验证软件应用程序的稳定性和可靠性。压力测试的目标是在极其沉重的负载条件下测量软件的健壮性和错误处理能力&#xff0c;并确保软件在危急情况下不会崩溃。它甚至可以测试超出正常工作点的测试&#xff0c;并评估软件在极端…

实现路由懒加载的方式有哪些?

1函数式懒加载 使用vue的异步组件和webpack的代码分割功能&#xff0c;通过&#xff08;&#xff09;>import()这种函数形式来定义路由组件&#xff0c;示例如下&#xff1a; const Home () > import(/views/Home.vue); const router new VueRouter({routes: [{ path…

PVE虚拟化平台之开启虚拟机IP显示方法

PVE虚拟化平台之开启虚拟机IP显示方法 一、PVE平台介绍1.1 PVE简介1.2 PVE特点1.3 PVE主要使用场景二、检查PVE环境2.1 环境介绍2.2 检查PVE和虚拟机状态三、虚拟机开启Qemu代理四、Linux虚拟机安装Guest-Agent4.1 进入虚拟机VNC控制台4.2 查看虚拟机IP五、Windows虚拟机安装Gu…

.NET 9 中的 多级缓存 HybridCache

HybridCache是什么 在 .NET 9 中&#xff0c;Microsoft 将 HybridCache 带入了框架体系。 HybridCache 是一种新的缓存模型&#xff0c;设计用于封装本地缓存和分布式缓存&#xff0c;使用者无需担心选择缓存类型&#xff0c;从而优化性能和维护效率。 实际上&#xff0c;Hybri…

Typesense:开源的高速搜索引擎

在当今数据驱动的世界中&#xff0c;高效、快速且智能的搜索能力是任何应用程序和网站成功的关键因素之一。无论是电商平台、内容管理系统还是社交媒体&#xff0c;用户都希望能够迅速找到所需信息。Typesense&#xff0c;作为一款优秀的开源搜索引擎&#xff0c;旨在通过其卓越…

frp 内网穿透

frp 在目前理解是一个提供端口转发的工具。不管是 windows 版本还是 linux 版本都同时提供了 frps 服务端与 frpc 客户端两个应用&#xff0c;分别对应 frps.toml 与 frpc.toml 两个配置文件。 下载地址 服务端 服务端需要有公网ip&#xff0c;接收请求转发到对应的客户端服务…

C语言结构体学习笔记

C语言结构体学习笔记 1、什么是结构体 结构体是一种用户自定义的数据类型&#xff0c;用于将不同类型的数据组合成一个有机整体。 例如&#xff0c;一个学生可以包含以下属性&#xff1a; int num; char name[20]; char sex; int age; char addr[30];这些属性可以通过结构体统…