Android T 分屏机制深度解析从SystemUI到SurfaceFlinger的全链路实现当我们在Android设备上流畅地使用分屏功能时背后隐藏着一套复杂的跨进程协作机制。本文将深入剖析Android T版本中分屏功能从SystemUI发起请求到最终在SurfaceFlinger完成图层合成的完整技术链路。1. 分屏机制的架构概览Android的分屏功能涉及多个系统组件的协同工作主要包括SystemUI作为用户交互的入口负责分屏请求的发起和界面控制WindowManagerService管理窗口层级和布局ActivityManagerService处理任务栈管理SurfaceFlinger负责最终的图层合成和显示这些组件通过Binder IPC进行跨进程通信而WindowContainerTransactionWCT则是贯穿整个流程的核心数据结构。2. SystemUI端的请求发起与处理2.1 从Launcher到SystemUI的跨进程调用分屏流程通常从Launcher开始通过SystemUiProxy发起跨进程调用// Launcher端发起分屏请求 mSystemUiProxy.startTasksWithLegacyTransition( taskIds[0], mainOpts.toBundle(), taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, splitRatio, adapter );这个调用会通过Binder到达SystemUI进程的SplitScreenController// SystemUI端接收请求 public void startTasksWithLegacyTransition(int mainTaskId, Bundle mainOptions, int sideTaskId, Bundle sideOptions, int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) { // 切换到主线程处理 executeRemoteCallWithTaskPermission(mController, startTasks, (controller) - controller.mStageCoordinator.startTasksWithLegacyTransition( mainTaskId, mainOptions, sideTaskId, sideOptions, sidePosition, splitRatio, adapter ) ); }2.2 WindowContainerTransaction的构建StageCoordinator是分屏功能的核心控制器它负责构建包含所有变更的WindowContainerTransactionprivate void startWithLegacyTransition(...) { // 初始化分屏布局 mSplitLayout.init(); // 创建WindowContainerTransaction对象 final WindowContainerTransaction wct new WindowContainerTransaction(); // 设置分屏位置比例 mSplitLayout.setDivideRatio(splitRatio); // 更新窗口边界 updateWindowBounds(mSplitLayout, wct); // 重新排序任务栈 wct.reorder(mRootTaskInfo.token, true); // 添加任务启动请求 wct.startTask(mainTaskId, mainOptions); wct.startTask(sideTaskId, sideOptions); // 应用事务 mTaskOrganizer.applyTransaction(wct); }3. WindowContainerTransaction的跨进程传递3.1 WCT的数据结构解析WindowContainerTransaction包含两种主要操作类型操作类型数据结构用途Change包含Configuration变更设置窗口边界、配置等HierarchyOp包含层级操作任务启动、重新排序等关键的数据结构构建过程// 设置窗口边界示例 public WindowContainerTransaction setBounds( NonNull WindowContainerToken container, NonNull Rect bounds) { Change chg getOrCreateChange(container.asBinder()); chg.mConfiguration.windowConfiguration.setBounds(bounds); chg.mConfigSetMask | ActivityInfo.CONFIG_WINDOW_CONFIGURATION; chg.mWindowSetMask | WindowConfiguration.WINDOW_CONFIG_BOUNDS; return this; } // 重新排序示例 public WindowContainerTransaction reorder( NonNull WindowContainerToken child, boolean onTop) { mHierarchyOps.add(HierarchyOp.createForReorder(child.asBinder(), onTop)); return this; }3.2 分屏边界的计算逻辑分屏布局的核心是SplitLayout类它负责计算分割线位置和各区域边界public void setDivideRatio(float ratio) { // 计算分割线位置 final int position isLandscape() ? mRootBounds.left (int)(mRootBounds.width() * ratio) : mRootBounds.top (int)(mRootBounds.height() * ratio); // 计算对齐目标 final DividerSnapAlgorithm.SnapTarget snapTarget mDividerSnapAlgorithm.calculateNonDismissingSnapTarget(position); // 设置分割线位置 setDividePosition(snapTarget.position, false); } private void updateBounds(int position) { // 更新分割线边界 mDividerBounds.set(mRootBounds); if (isLandscape(mRootBounds)) { position mRootBounds.left; mDividerBounds.left position - mDividerInsets; mDividerBounds.right mDividerBounds.left mDividerWindowWidth; mBounds1.right position; mBounds2.left mBounds1.right mDividerSize; } else { position mRootBounds.top; mDividerBounds.top position - mDividerInsets; mDividerBounds.bottom mDividerBounds.top mDividerWindowWidth; mBounds1.bottom position; mBounds2.top mBounds1.bottom mDividerSize; } }4. 分屏窗口的特殊处理4.1 SplitWindowManager与分割线窗口分屏功能使用特殊的SplitWindowManager来管理分割线窗口这类窗口不会出现在常规的dumpsys window windows输出中void init(SplitLayout splitLayout, InsetsState insetsState) { // 创建SurfaceControlViewHost mViewHost new SurfaceControlViewHost(mContext, mContext.getDisplay(), this); // 加载分割线视图 mDividerView (DividerView) LayoutInflater.from(mContext) .inflate(R.layout.split_divider, null); // 设置窗口参数 WindowManager.LayoutParams lp new WindowManager.LayoutParams( dividerBounds.width(), dividerBounds.height(), TYPE_DOCK_DIVIDER, FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY, PixelFormat.TRANSLUCENT); // 设置特殊标志 lp.privateFlags | PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY; // 添加视图到窗口 mViewHost.setView(mDividerView, lp); }4.2 分屏任务的层级管理分屏功能使用特殊的任务栈结构#0 Task4 typeundefined modefullscreen #1 Task6 typeundefined modemulti-window #0 Task5 typeundefined modemulti-window其中Task 4是根任务栈Task 5和6分别对应主分屏和次分屏的任务栈5. SurfaceFlinger端的最终合成5.1 分屏图层的特殊处理在SurfaceFlinger中分屏相关的图层会带有特殊标记 Layer 0x7a8f4d0c00 (Divider) Region: [0,0][1440,10] Flags: 0x40000000 (TRUSTED_OVERLAY) BufferQueue: [1440x10:1440x10,1]可以通过以下命令查看分屏相关的图层信息adb shell dumpsys SurfaceFlinger | grep -A 10 Divider5.2 分屏动画的同步机制分屏功能使用SyncQueue来确保布局变更和动画的同步mSyncQueue.runInSync(t - { // 显示分割线 setDividerVisibility(true, t); // 更新Surface边界 updateSurfaceBounds(mSplitLayout, t, false); });这种同步机制避免了分屏过程中可能出现的视觉闪烁或布局不一致问题。6. 分屏问题的调试技巧6.1 常用调试命令查看窗口层级adb shell dumpsys window windows查看分屏任务信息adb shell dumpsys activity containers查看SurfaceFlinger图层adb shell dumpsys SurfaceFlinger6.2 常见问题排查分屏边界不正确检查SplitLayout的updateBounds计算动画卡顿检查RemoteAnimationAdapter的实现和同步机制窗口层级异常验证WindowContainerTransaction中的reorder操作7. 车载与手机分屏的差异在车载系统中分屏功能需要考虑更多特殊场景屏幕比例车载屏幕通常更宽需要调整分割比例算法输入焦点需要更复杂的焦点管理逻辑安全限制某些驾驶模式下可能限制分屏功能车载分屏的关键修改点通常集中在SplitLayout和StageCoordinator类中。