OpenHarmony 窗口创建与管理分析
基于
foundation/window/window_manager/源码
目录
术语
| 缩写 | 全称 | 说明 |
|---|---|---|
| WMS | WindowManagerService | 窗口管理服务(服务端核心) |
| WM | WindowManager | 窗口管理器(客户端 API) |
| WindowNode | — | 服务端窗口节点,对应一个窗口实例 |
| WindowNodeContainer | — | 每显示器的窗口节点容器,管理 Z-order 树 |
| Session | — | SceneBoard 架构中的窗口会话,替代 WindowNode |
| SceneBoard | — | OHOS 桌面窗口管理器(类似 Android Launcher 的窗口管理扩展) |
| StartingWindow | — | 启动窗口(应用冷启动时的占位窗口) |
| AvoidArea | — | 安全区域(状态栏、导航栏等占据的区域) |
| RS | Render Service | 渲染服务,窗口的渲染 surface 由其管理 |
| ZOrder | Z-Order | 窗口在 Z 轴上的堆叠顺序 |
| Ability | — | OHOS 应用/功能的基本运行单元 |
| SceneSession | — | SceneBoard 管理的场景会话 |
| HDI | Hardware Display Interface | 显示硬件抽象层 |
1. 概述
OpenHarmony 的窗口管理子系统(foundation/window/window_manager/)是系统 UI 的核心基础设施,负责所有窗口的创建、销毁、布局、Z-Order 管理、焦点分发、输入事件路由以及安全区域计算。
整体架构一句话: 应用进程通过 libwm(客户端 SDK)向 WindowManagerService(服务端)请求窗口创建/管理,服务端维护以 WindowNode(经典架构)或 Session(SceneBoard 架构)为节点的窗口树,通过 Z-Order 策略和布局策略控制窗口在屏幕上的呈现。
窗口分类:
| 分类 | 类型范围 | 典型窗口 | 创建方 |
|---|---|---|---|
| 应用主窗口 | WINDOW_TYPE_APP_MAIN_WINDOW | 应用主界面 | 应用 Ability |
| 应用子窗口 | WINDOW_TYPE_APP_SUB_WINDOW | 弹窗、浮层 | 应用 |
| 系统窗口(应用层以下) | WINDOW_TYPE_WALLPAPER / DESKTOP | 壁纸、桌面 | 系统 |
| 系统窗口(应用层以上) | STATUS_BAR / NAV_BAR / KEYGUARD / FLOAT / PIP / DIALOG / TOAST / LAUNCHER / SCENE_BOARD 等 | 状态栏、导航栏、锁屏、悬浮窗、画中画、对话框 | 系统 |
| 系统子窗口 | SYSTEM_SUB_WINDOW / SCB_SUB_WINDOW | 系统场景子窗口 | 系统 |
| UIExtension | WINDOW_TYPE_UI_EXTENSION | 安全浮层(如密码输入框) | 应用/系统 |
核心能力一览:
| 能力 | 实现组件 | 说明 |
|---|---|---|
| 窗口创建/销毁 | WindowImpl::Create / WindowRoot::Destroy | 客户端请求 → 服务端创建节点 |
| Z-Order 管理 | WindowZorderPolicy | 根据窗口类型和优先级分配 Z 轴顺序 |
| 布局策略 | WindowLayoutPolicy (Cascade / Tile) | 窗口尺寸、位置、分屏管理 |
| 焦点管理 | WindowNodeContainer::SetFocusWindow | 输入焦点切换 |
| 安全区域 | AvoidAreaController | 计算系统栏、凹口等区域 |
| 启动窗口 | StartingWindow | 冷启动/热启动占位界面 |
| 窗口动画 | RemoteAnimation | 窗口切换动画 |
| 渲染绑定 | RSSurfaceNode | 每个窗口绑定一个 RS 渲染节点 |
2. 目录结构
foundation/window/window_manager/
├── wm/ ← 客户端 SDK(libwm,供应用使用)
│ ├── include/
│ │ ├── window.h / window_impl.h ← 窗口接口 / 实现(旧架构)
│ │ ├── window_session_impl.h ← Session 架构窗口实现
│ │ ├── window_manager.h ← 窗口管理器客户端 API
│ │ ├── window_option.h ← 窗口创建参数
│ │ ├── window_adapter.h ← IPC 桥接(连接 WMS)
│ │ ├── window_agent.h ← 窗口代理(服务端回调窗口)
│ │ ├── window_scene.h ← 场景窗口
│ │ ├── root_scene.h ← 根场景
│ │ └── zidl/ ← IPC 接口定义
│ └── src/
│ ├── window_impl.cpp ← 窗口创建/销毁/属性管理
│ ├── window_session_impl.cpp ← Session 架构窗口实现
│ ├── window_manager.cpp ← WindowManager 单例实现
│ ├── window_adapter.cpp ← IPC 调用 WMS 服务
│ ├── window_option.cpp ← 窗口选项
│ └── ...
├── wmserver/ ← 服务端 SDK(libsms)
│ ├── include/
│ │ ├── window_manager_service.h ← WMS 主服务
│ │ ├── window_controller.h ← 窗口操作控制器
│ │ ├── window_root.h ← 窗口根(管理每显示器的窗口树)
│ │ ├── window_node.h ← 服务端窗口节点
│ │ ├── window_node_container.h ← 窗口节点容器(每显示器)
│ │ ├── window_layout_policy.h ← 窗口布局策略
│ │ ├── window_zorder_policy.h ← Z-Order 分配策略
│ │ ├── avoid_area_controller.h ← 安全区域控制
│ │ ├── starting_window.h ← 启动窗口
│ │ └── zidl/ ← IPC 接口定义
│ └── src/
│ ├── window_manager_service.cpp ← 服务入口
│ ├── window_controller.cpp ← 创建/销毁窗口
│ ├── window_root.cpp ← 窗口树管理
│ ├── window_layout_policy.cpp ← 布局算法
│ └── ...
├── window_scene/ ← SceneBoard 会话管理
│ ├── session/ ← Session 核心实现
│ │ ├── host/
│ │ │ ├── session.h/cpp ← Session 基类
│ │ │ ├── scene_session.h/cpp ← 场景会话
│ │ │ ├── main_session.h/cpp ← 主窗口会话
│ │ │ ├── sub_session.h/cpp ← 子窗口会话
│ │ │ ├── system_session.h/cpp ← 系统窗口会话
│ │ │ ├── keyboard_session.h/cpp ← 键盘会话
│ │ │ └── root_scene_session.h/cpp ← 根场景会话
│ │ └── container/
│ │ └── window_event_channel.h/cpp ← 窗口事件通道
│ ├── session_manager/ ← 会话管理器
│ ├── session_manager_service/ ← 会话管理器服务
│ ├── screen_session_manager/ ← 屏幕会话管理
│ └── screen_session_manager_client/ ← 屏幕会话客户端
├── extension/ ← UIExtension 窗口扩展
├── interfaces/ ← 对外接口定义
│ ├── innerkits/wm/ ← C++ SDK 接口头文件
│ └── kits/ ← JS/N-API 接口
├── dm/ / dm_lite/ ← 显示管理器
└── test/ / previewer/ ← 测试/预览器
3. 两代架构
OHOS 窗口管理经历了从经典 WMS 到 Scene Session 两代架构演变。
3.1 经典 WMS 架构
经典架构是 OHOS 3.x / 4.x 的主要窗口管理方式:
应用进程 (Client) render_service 进程
│ │
├── WindowImpl │
│ ├── WindowOption (创建参数) │
│ ├── WindowProperty (窗口属性) │
│ ├── RSSurfaceNode (渲染 Surface) │
│ └── WindowAgent (代理回调) │
│ │
└── WindowAdapter ── IPC ──→ WindowManagerService
│
├── WindowController
│ └── 生成 windowId
│ └── 创建 WindowNode
│
├── WindowRoot
│ └── WindowNodeContainer
│ ├── WindowNode 树
│ ├── ZOrder 排序
│ └── 布局策略
│
└── 通知 WindowManagerAgent
→ 上报焦点/可见性/布局变化
核心组件:
| 组件 | 所在位置 | 职责 |
|---|---|---|
WindowImpl |
wm/ | 客户端窗口对象,管理属性、事件、生命周期 |
WindowOption |
wm/ | 窗口创建参数(类型、模式、矩形、标志等) |
WindowAgent |
wm/ | 窗口代理对象,作为 IPC 回调的接收端 |
WindowAdapter |
wm/ | 桥接类,封装对 WMS 的 IPC 调用 |
WindowManagerService |
wmserver/ | 服务端主入口,序列化所有窗口操作 |
WindowController |
wmserver/ | 窗口操作控制器,协调 WindowRoot 和输入 |
WindowRoot |
wmserver/ | 窗口树根,管理每显示器的 WindowNodeContainer |
WindowNodeContainer |
wmserver/ | 按显示器的窗口容器,维护窗口节点树 + Z-Order |
WindowNode |
wmserver/ | 服务端窗口节点,持有属性、Surface、回调 |
3.2 Scene Session 架构
Scene Session 架构从 OHOS 5.x 开始引入,与 SceneBoard 桌面环境配合使用:
应用进程 SceneBoard 进程 (桌面)
│ │
├── WindowSessionImpl │
│ ├── 通过 ISession 连接 SceneBoard │
│ └── WindowEventChannel (事件通道) │
│ │
└── IPC ──→ SceneSessionManager
│
├── SessionManagerService
│
└── Session 树
├── RootSceneSession
├── MainSession (应用主窗口)
├── SubSession (应用子窗口)
├── SystemSession (系统窗口)
└── KeyboardSession (键盘)
Session 继承体系:
Session (基类)
├── SceneSession
│ ├── MainSession — 应用主窗口
│ ├── SubSession — 应用子窗口
│ ├── SystemSession — 系统窗口
│ ├── KeyboardSession — 键盘面板
│ └── RootSceneSession — 根场景
└── ScbSystemSession — SceneBoard 系统窗口
3.3 两代架构关系
| 维度 | 经典 WMS | Scene Session |
|---|---|---|
| 服务端表示 | WindowNode |
Session / SceneSession |
| 客户端实现 | WindowImpl |
WindowSessionImpl |
| 服务入口 | WindowManagerService |
SessionManagerService |
| 树容器 | WindowNodeContainer |
Session 管理树 |
| IPC 通道 | WindowAdapter → IWindowManager |
ISession → SessionStage |
| 桌面环境 | 传统桌面/无桌面 | SceneBoard 桌面 |
| 事件通道 | InputTransferStation |
WindowEventChannel |
| 布局策略 | WindowLayoutPolicy |
LayoutController |
| 启动窗口 | StartingWindow(独立的窗口节点) |
Starting window 集成在 Session 中 |
| 兼容性 | 所有窗口类型 | 主要配合 SceneBoard 使用 |
两套架构并非替代关系,而是共存——WindowImpl 和 WindowSessionImpl 都实现了 Window 接口,通过 WindowOption 的 SetWindowSessionType() 来区分走哪条路径。
4. 窗口类型体系
窗口类型由 WindowType 枚举定义(interfaces/innerkits/wm/wm_common.h),按数值范围分层:
// wm_common.h:116
enum class WindowType : uint32_t {
APP_WINDOW_BASE = 1,
APP_MAIN_WINDOW_BASE = APP_WINDOW_BASE,
WINDOW_TYPE_APP_MAIN_WINDOW = APP_MAIN_WINDOW_BASE, // 1
APP_MAIN_WINDOW_END,
APP_SUB_WINDOW_BASE = 1000,
WINDOW_TYPE_MEDIA = APP_SUB_WINDOW_BASE, // 1000
WINDOW_TYPE_APP_SUB_WINDOW, // 1001
WINDOW_TYPE_APP_COMPONENT, // 1002
APP_SUB_WINDOW_END,
APP_WINDOW_END = APP_SUB_WINDOW_END,
SYSTEM_WINDOW_BASE = 2000,
// BELOW_APP 层 - 应用窗口之下
WINDOW_TYPE_WALLPAPER = SYSTEM_WINDOW_BASE, // 2000
WINDOW_TYPE_DESKTOP, // 2001
BELOW_APP_SYSTEM_WINDOW_END,
// ABOVE_APP 层 - 应用窗口之上
ABOVE_APP_SYSTEM_WINDOW_BASE = 2100,
WINDOW_TYPE_APP_LAUNCHING, // 2100
WINDOW_TYPE_DOCK_SLICE, // 2101
WINDOW_TYPE_INCOMING_CALL, // 2102
WINDOW_TYPE_SEARCHING_BAR, // 2103
WINDOW_TYPE_SYSTEM_ALARM_WINDOW, // 2104
WINDOW_TYPE_INPUT_METHOD_FLOAT, // 2105
WINDOW_TYPE_FLOAT, // 2106
WINDOW_TYPE_TOAST, // 2107
WINDOW_TYPE_STATUS_BAR, // 2108
WINDOW_TYPE_PANEL, // 2109
WINDOW_TYPE_KEYGUARD, // 2110
WINDOW_TYPE_VOLUME_OVERLAY, // 2111
WINDOW_TYPE_NAVIGATION_BAR, // 2112
WINDOW_TYPE_LAUNCHER_RECENT, // 2115
WINDOW_TYPE_SCENE_BOARD, // 2122
WINDOW_TYPE_PIP, // 2118
WINDOW_TYPE_KEYBOARD_PANEL, // 2124
// ... 更多类型 ...
ABOVE_APP_SYSTEM_WINDOW_END,
SYSTEM_SUB_WINDOW_BASE = 2500,
WINDOW_TYPE_SYSTEM_SUB_WINDOW, // 2500
WINDOW_TYPE_SCB_SUB_WINDOW, // 2501
SYSTEM_SUB_WINDOW_END,
SYSTEM_WINDOW_END = SYSTEM_SUB_WINDOW_END,
WINDOW_TYPE_UI_EXTENSION = 3000 // 3000
};
分层示意图:
Z 轴(从下到上)
│
├── UI_EXTENSION (3000) 安全浮层(密码输入等)
│
├── SYSTEM_SUB_WINDOW (2500) SceneBoard 子窗口
│
├── ABOVE_APP 系统窗口 (2100+)
│ ├── SCENE_BOARD (2122) SceneBoard 桌面
│ ├── LAUNCHER_RECENT (2115) 最近任务
│ ├── NAVIGATION_BAR (2112) 导航栏
│ ├── STATUS_BAR (2108) 状态栏
│ ├── KEYGUARD (2110) 锁屏
│ ├── VOLUME_OVERLAY (2111) 音量面板
│ ├── FLOAT (2106) 悬浮窗
│ ├── TOAST (2107) Toast 提示
│ ├── SYSTEM_ALARM (2104) 系统闹钟
│ ├── INCOMING_CALL (2102) 来电
│ ├── DOCK_SLICE (2101) Dock 栏
│ └── APP_LAUNCHING (2100) 应用启动屏
│
├── 应用窗口 (1 / 1000+)
│ ├── APP_SUB_WINDOW (1001) 子窗口(对话框等)
│ ├── APP_COMPONENT (1002) 组件窗口
│ ├── MEDIA (1000) 媒体窗口
│ └── APP_MAIN_WINDOW (1) 应用主窗口
│
└── BELOW_APP (2000+)
├── DESKTOP (2001) 桌面
└── WALLPAPER (2000) 壁纸
窗口层次规则:
| 位置 | Z-order 范围 | 说明 |
|---|---|---|
| BELOW_APP | 最低 | 在应用窗口之下(壁纸/桌面) |
| 应用窗口 | 中间 | APP_MAIN / APP_SUB / MEDIA / COMPONENT |
| ABOVE_APP | 较高 | 系统 UI 元素(状态栏/导航栏/悬浮窗等) |
| SYSTEM_SUB | 接近最高 | SceneBoard 系统子窗口 |
| UI_EXTENSION | 最高 | 安全上下文窗口,独立层次 |
5. 应用窗口创建流程
5.1 客户端:WindowImpl::Create
应用通过 Window::Create() 创建窗口时,最终进入 WindowImpl::Create()(wm/src/window_impl.cpp:1541):
// window_impl.cpp:1541
WMError WindowImpl::Create(uint32_t parentId,
const std::shared_ptr<AbilityRuntime::Context>& context)
{
// 1. 参数校验
WMError ret = WindowCreateCheck(parentId);
if (ret != WMError::WM_OK) return ret;
// 2. 初始化显示和上下文
SetDefaultDisplayIdIfNeed();
context_ = context;
// 3. 创建窗口代理(服务端回调用)
sptr<IWindow> windowAgent(new WindowAgent(window));
// 4. 获取 Ability token(用于关联启动窗口)
sptr<IRemoteObject> token = context_ ? context_->GetToken() : nullptr;
// 5. 调整属性(根据 API 版本、窗口类型)
ChangePropertyByApiVersion();
InitAbilityInfo();
SetSystemConfig();
// 6. 通过 WindowAdapter 发起 IPC 创建请求
ret = SingletonContainer::Get<WindowAdapter>()
.CreateWindow(windowAgent, property_, surfaceNode_, windowId, token);
// 7. 注册窗口到全局映射表
{
std::unique_lock<std::shared_mutex> lock(windowMapMutex_);
windowMap_.insert({name_, {windowId, self}});
}
// 子窗口关联到父窗口
if (parentId != INVALID_WINDOW_ID) {
subWindowMap_[property_->GetParentId()].push_back(window);
}
// 8. 注册输入通道
InputTransferStation::GetInstance().AddInputWindow(self);
state_ = WindowState::STATE_CREATED;
return ret;
}
创建流程分步说明:
| 步骤 | 操作 | 关键代码 |
|---|---|---|
| 1 | 检查窗口创建合法性(父窗口是否存在、类型是否合法) | WindowCreateCheck(parentId) |
| 2 | 设置默认 DisplayId、绑定上下文 | SetDefaultDisplayIdIfNeed() |
| 3 | 创建 WindowAgent(IPC 回调代理) |
new WindowAgent(window) |
| 4 | 获取 Ability token | context_->GetToken() |
| 5 | 调整属性(API 版本兼容、类型默认值) | ChangePropertyByApiVersion() |
| 6 | 核心:通过 IPC 请求服务端创建窗口 | WindowAdapter::CreateWindow() |
| 7 | 注册到本地窗口映射表 | windowMap_.insert() |
| 8 | 注册输入事件通道 | AddInputWindow() |
5.2 IPC 桥接:WindowAdapter
WindowAdapter 是客户端与服务端之间的 IPC 桥接层。CreateWindow() 将创建参数序列化后通过 Binder 发送到 WMS:
// WindowAdapter 封装了对 IWindowManager 的 IPC 调用
class WindowAdapter : public RefBase {
WMError CreateWindow(sptr<IWindow>& window, sptr<WindowProperty>& property,
std::shared_ptr<RSSurfaceNode> surfaceNode,
uint32_t& windowId, const sptr<IRemoteObject>& token);
// ...
};
IPC 接口定义在 zidl/ 目录:
IWindowManager— 客户端→服务端(创建/销毁/更新窗口)IWindow— 服务端→客户端(通知窗口事件)IWindowManagerAgent— 服务端→客户端(广播窗口状态变化)
5.3 服务端:WindowManagerService
服务端的 WindowManagerService::CreateWindow()(wmserver/src/window_manager_service.cpp:958)在 WMS 线程中处理:
// window_manager_service.cpp:958
WMError WindowManagerService::CreateWindow(sptr<IWindow>& window,
sptr<WindowProperty>& property,
const std::shared_ptr<RSSurfaceNode>& surfaceNode,
uint32_t& windowId, sptr<IRemoteObject> token)
{
// 1. 安全检查(系统窗口权限)
// 2. 设置调用者信息
property->isSystemCalling_ = Permission::IsSystemCalling();
// 3. 通过 PostSyncTask 投递到 WMS 主线程执行
auto task = [this, pid, uid, &window, &property, &surfaceNode,
&windowId, &token]() {
return windowController_->CreateWindow(window, property,
surfaceNode, windowId, token, pid, uid);
};
WMError ret = PostSyncTask(task, "CreateWindow");
// 4. 记录调用者 access token
accessTokenIdMaps_.insert({windowId, IPCSkeleton::GetCallingTokenID()});
return ret;
}
WindowController::CreateWindow()(wmserver/src/window_controller.cpp)执行实际的创建逻辑:
// window_controller.cpp
WMError WindowController::CreateWindow(sptr<IWindow>& window,
sptr<WindowProperty>& property,
const std::shared_ptr<RSSurfaceNode>& surfaceNode,
uint32_t& windowId, sptr<IRemoteObject> token,
int32_t pid, int32_t uid)
{
// 1. 生成窗口 ID
windowId = GenWindowId();
// 2. 创建 WindowNode(服务端窗口节点)
sptr<WindowNode> node = new WindowNode(property, window, surfaceNode, pid, uid);
// 3. 绑定屏幕和 DisplayId
sptr<DisplayInfo> displayInfo = ...;
node->SetDisplayId(displayInfo->GetId());
// 4. 添加到窗口树
WMError ret = windowRoot_->SaveWindow(node);
if (ret != WMError::WM_OK) return ret;
// 5. 注册死亡通知
windowRoot_->AddDeathRecipient(node);
// 6. 将节点插入窗口树
return windowRoot_->AddWindowNode(parentId, node);
}
5.4 窗口节点树:WindowRoot
WindowRoot 管理每个屏幕的窗口节点容器 WindowNodeContainer:
WindowRoot (单例)
├── 屏幕 0 (built-in)
│ └── WindowNodeContainer
│ ├── Below 层
│ │ ├── WindowNode (壁纸, type=2000)
│ │ └── WindowNode (桌面, type=2001)
│ ├── App 层
│ │ ├── WindowNode (应用 A, type=1)
│ │ ├── WindowNode (应用 A 子窗口, type=1001)
│ │ └── WindowNode (应用 B, type=1)
│ └── Above 层
│ ├── WindowNode (状态栏, type=2108)
│ ├── WindowNode (导航栏, type=2112)
│ ├── WindowNode (悬浮窗, type=2106)
│ └── WindowNode (Toast, type=2107)
│
└── 屏幕 1 (外接)
└── WindowNodeContainer
└── ...
WindowNode 结构:(wmserver/include/window_node.h)
| 属性 | 类型 | 说明 |
|---|---|---|
property_ |
sptr<WindowProperty> |
窗口属性(类型/模式/矩形/透明度等) |
windowToken_ |
sptr<IWindow> |
窗口的 IPC 回调接口(服务端→客户端) |
surfaceNode_ |
shared_ptr<RSSurfaceNode> |
RS 渲染节点(绑定到渲染管线) |
children_ |
std::vector<sptr<WindowNode>> |
子窗口列表 |
callingPid_/callingUid_ |
int32_t |
调用者进程/用户 ID |
displayId_ |
DisplayId |
所属显示器 |
添加到窗口树的流程:
// WindowNodeContainer::AddWindowNode
// 1. 根据窗口类型确定父容器层(Below/App/Above)
// 2. 调用 AssignZOrder() 分配 Z-Order
// → WindowZorderPolicy 基于窗口类型和优先级计算
// 3. 将节点插入对应层的链表
// 4. 触发布局重新计算(LayoutPolicy)
// 5. 通知窗口代理(IWindow::UpdateWindowRect)
// 6. 通知其他监听器(焦点、可见性、安全区域变化)
5.5 窗口与 Display 的关系
窗口通过 DisplayId 关联到物理显示器,这个关联贯穿客户端和服务端:
客户端侧的 Display 分配:
// window_impl.cpp:1529
void WindowImpl::SetDefaultDisplayIdIfNeed()
{
auto displayId = property_->GetDisplayId();
if (displayId == DISPLAY_ID_INVALID) {
auto defaultDisplayId = SingletonContainer::IsDestroyed() ? DISPLAY_ID_INVALID :
SingletonContainer::Get<DisplayManager>().GetDefaultDisplayId();
property_->SetDisplayId(defaultDisplayId);
}
}
服务端侧的 Display 分配:
// window_root.cpp:814
WMError WindowRoot::AddWindowNode(uint32_t parentId, sptr<WindowNode>& node, bool fromStartingWin)
{
// 根据节点的 displayId 获取或创建对应显示器的容器
auto container = GetOrCreateWindowNodeContainer(node->GetDisplayId());
if (container == nullptr) {
return WMError::WM_ERROR_INVALID_DISPLAY;
}
// ...
return container->AddWindowNode(node, parentNode);
}
窗口与 Display 的一对多映射:
WindowRoot (全局单例)
├── displayId=0 (内置屏)
│ └── WindowNodeContainer
│ ├── WindowNode A (displayId=0)
│ ├── WindowNode B (displayId=0)
│ └── ...
│
├── displayId=1 (外接屏)
│ └── WindowNodeContainer
│ ├── WindowNode C (displayId=1)
│ └── ...
│
└── displayId=999 (折叠副屏)
└── WindowNodeContainer
└── ...
核心规则:
| 规则 | 说明 |
|---|---|
| 一个窗口只属于一个显示器 | 由 WindowProperty::displayId_ 标识 |
| 默认分配到主屏 | SetDefaultDisplayIdIfNeed() → DisplayManager::GetDefaultDisplayId() |
| 创建时可指定 | WindowOption::SetDisplayId(displayId) |
| 跨屏展示 | WindowNode::SetShowingDisplays() 记录窗口内容可见于哪些显示器(如折叠屏展开时可见于两个屏) |
| 容器隔离 | 每个 WindowNodeContainer 独立管理 Z-Order、布局策略和焦点 |
| 焦点独立 | 每个显示器的 WindowNodeContainer 有独立的 SetFocusWindow() |
DisplayId 的后续影响:
- 渲染:
RSSurfaceNode的绘制输出路由到对应 Display 的合成队列 - 输入:触摸/鼠标事件的坐标转换基于窗口所在的 Display 坐标系
- 安全区域:
AvoidAreaController按 Display 计算状态栏/导航栏/挖孔区域 - 帧率:HGM 按 Display 独立管理刷新率策略
6. 系统窗口创建与管理
6.1 系统窗口类型
系统窗口分为三个子层次,基值从 2000 开始:
| 层次 | 枚举范围 | 包含类型 | 典型位置 |
|---|---|---|---|
| BELOW_APP | 2000~2001 | WALLPAPER, DESKTOP | 应用窗口之下 |
| ABOVE_APP | 2100~2199 | STATUS_BAR, NAVIGATION_BAR, KEYGUARD, FLOAT, TOAST, PANEL, DIALOG, SCENE_BOARD, PIP, SCREENSHOT, VOLUME_OVERLAY 等约 30 种 | 应用窗口之上 |
| SYSTEM_SUB | 2500~2501 | SYSTEM_SUB_WINDOW, SCB_SUB_WINDOW | 系统子窗口(最高层) |
6.2 系统窗口创建
系统窗口的创建流程与应用窗口类似,关键区别:
- 应用窗口:由应用 Ability 通过 WindowManager::CreateWindow 创建
+ 系统窗口:由系统服务(SystemUI / System Ability)调用 WindowManager 接口创建
系统窗口的 WindowOption 配置:
// 系统窗口创建示例
sptr<WindowOption> option = new WindowOption();
option->SetWindowType(WindowType::WINDOW_TYPE_STATUS_BAR);
option->SetWindowMode(WindowMode::WINDOW_MODE_FULLSCREEN);
option->SetWindowRect({0, 0, screenWidth, statusBarHeight});
option->SetFocusable(false);
option->SetTouchable(true);
// ... 创建窗口
6.3 系统窗口权限控制
系统窗口有严格的权限检查(WindowManagerService::CreateWindow 中执行):
CreateWindow() 中:
1. 如果是 SYSTEM_WINDOW 类型
2. 检查调用者是否系统级进程(isSystemCalling_)
3. 非系统进程尝试创建系统窗口 → 返回 WMError::WM_ERROR_INVALID_TYPE
这种检查确保普通应用无法随意创建系统级窗口,防止恶意覆盖系统 UI。
7. 窗口生命周期管理
7.1 状态机
每个 WindowNode 通过 WindowNodeStateMachine 管理生命周期状态:
创建
│
▼
┌────────────┐
│ CREATED │
└─────┬──────┘
│ Show
▼
┌────────────┐
│ SHOWN │◄────── Show
└─────┬──────┘
│ Hide
▼
┌────────────┐
│ HIDDEN │──► Destroy ──► DESTROYED
└────────────┘
| 状态 | 含义 | 触发操作 |
|---|---|---|
| CREATED | 窗口节点已创建,但未显示 | CreateWindow() |
| SHOWN | 窗口显示在屏幕上 | Show() / NotifyWindowTransition() |
| HIDDEN | 窗口被隐藏(仍在树中) | Hide() / 后台化 |
| DESTROYED | 窗口被销毁 | DestroyWindow() |
7.2 焦点管理
焦点管理通过 WindowNodeContainer::SetFocusWindow() 实现:
// window_node_container.cpp
WMError WindowNodeContainer::SetFocusWindow(uint32_t windowId)
{
// 1. 解焦当前焦点窗口
sptr<WindowNode> curFocusedNode = ...;
curFocusedNode->SetFocusFlag(false);
// 2. 设置新焦点
sptr<WindowNode> newFocusedNode = FindNode(windowId);
newFocusedNode->SetFocusFlag(true);
// 3. 广播焦点变化
NotifyFocusChange(newFocusedNode, curFocusedNode);
// 4. 更新输入通道焦点
inputWindowMonitor_->UpdateFocus(windowId);
}
焦点分配规则:
| 规则 | 说明 |
|---|---|
| 仅 SHOWN 状态的窗口可获焦 | 隐藏/销毁窗口不能获取焦点 |
| 仅 focusable 的窗口可获焦 | 状态栏/导航栏通常不可焦点 |
| 应用窗口按点击顺序获焦 | 用户点击的窗口获取焦点 |
| 系统弹出窗口(Dialog/Float)可获焦 | 但有限制:需要对应权限 |
| 焦点切换触发回调 | 通过 IFocusChangedListener 通知客户端 |
7.3 Z-Order 管理
Z-Order 由 WindowZorderPolicy 管理,在每次添加窗口节点时重新分配:
// window_zorder_policy.cpp — 简化的分配逻辑
void WindowZorderPolicy::AssignZOrder(sptr<WindowNode>& node,
sptr<WindowNodeContainer>& container)
{
// 1. 确定窗口层次层(Below / App / Above)
WindowLayer layer = GetWindowLayer(node->GetWindowType());
// 2. 在层内按类型优先级计算 Z-order
int zOrder = CalculateTypePriority(node->GetWindowType());
// 3. 同类型窗口按创建顺序排列
zOrder += container->GetWindowCountByType(node->GetWindowType());
node->SetZOrder(zOrder);
}
Z-Order 分层优先级:
| 优先级顺序(从低到高) | 窗口类型 |
|---|---|
| 1 (最低) | WALLPAPER |
| 2 | DESKTOP |
| 3~n | 应用主窗口 + 子窗口 |
| n+1 | SCENE_BOARD |
| n+2 | LAUNCHER_RECENT, SEARCHING_BAR |
| n+3 | STATUS_BAR, PANEL |
| n+4 | DOCK_SLICE, NAVIGATION_BAR |
| n+5 | KEYGUARD, INCOMING_CALL, SYSTEM_ALARM |
| n+6 | FLOAT, DIALOG, TOAST, PIP |
| n+7 | SYSTEM_SUB_WINDOW, SCB_SUB_WINDOW |
| max | UI_EXTENSION |
7.4 布局策略
WindowLayoutPolicy 提供两种布局模式,用于管理分屏和悬浮窗口:
| 布局模式 | 策略类 | 说明 |
|---|---|---|
| 级联 (Cascade) | WindowLayoutPolicyCascade |
窗口层叠排列,可拖动/缩放 |
| 平铺 (Tile) | WindowLayoutPolicyTile |
窗口分屏/网格排列(Split Screen) |
布局策略在每个显示器的 WindowNodeContainer 中生效,在窗口添加/删除/大小变化时触发重排。布局策略负责:
- 计算窗口可用空间
- 设置窗口显示位置和大小
- 处理分屏切换(从 Tile 到 Cascade 或反之)
- 管理悬浮窗口的默认位置
8. Scene Session 架构详解
8.1 Session 继承体系
Session 架构是 OHOS 5.x+ 引入的新一代窗口管理模型,与 SceneBoard 桌面环境深度集成:
Session (基类) ← `window_scene/session/host/include/session.h`
├── 属性:persistentId, sessionInfo, windowSessionProperty
├── 方法:Show(), Hide(), Disconnect(), ProcessBackEvent()
├── 回调:SessionStage(客户端窗口阶段)
│
├── SceneSession ← `scene_session.h`
│ ├── 场景窗口通用实现
│ ├── 管理 RSSurfaceNode + WindowEventChannel
│ │
│ ├── MainSession ← `main_session.h`
│ │ ├── 应用主窗口(对应 APP_MAIN_WINDOW)
│ │ ├── 管理布局控制器 LayoutController
│ │ └── 处理分屏/悬浮/全屏模式切换
│ │
│ ├── SubSession ← `sub_session.h`
│ │ ├── 应用子窗口(对应 APP_SUB_WINDOW)
│ │ └── 跟随父窗口生命周期
│ │
│ ├── SystemSession ← `system_session.h`
│ │ ├── 系统窗口(状态栏/导航栏/音量面板等)
│ │ ├── 权限校验(只有系统进程可创建)
│ │ └── 悬浮球窗口管理(Floating Ball)
│ │
│ ├── KeyboardSession ← `keyboard_session.h`
│ │ └── 输入法键盘面板
│ │
│ └── RootSceneSession ← `root_scene_session.h`
│ └── 根场景会话(SceneBoard 的顶层容器)
│
└── ScbSystemSession ← `scb_system_session.h`
└── SceneBoard 系统窗口(SystemUI 内部使用)
8.2 SceneBoard 窗口管理
SceneBoard 是一个系统级桌面进程(类似 Android Launcher + WindowManager 的部分能力),它通过 SessionManager 管理所有窗口:
SceneBoard 进程
│
├── SceneSessionManager
│ ├── 注册所有 Session
│ ├── 管理 Session 生命周期
│ └── 协调 Z-Order 和焦点
│
├── SessionManagerService(IPC 服务)
│ ├── 接收来自应用的 Session 请求
│ └── 分发给 SceneSessionManager
│
└── ScreenSessionManager
├── 管理屏幕会话
└── 处理多屏/折叠屏事件
8.3 窗口与 Session 的绑定
WindowSessionImpl 是客户端 Window 接口的 Session 架构实现。当 WindowSessionType 设置为 Session 模式时,窗口不是直接通过 WMS 创建,而是绑定到一个已有的 Session:
// window_session_impl.h:101
class WindowSessionImpl : public Window {
WMError Create(const std::shared_ptr<AbilityRuntime::Context>& context,
const sptr<Rosen::ISession>& iSession, // 来自 SceneBoard 的 Session 接口
const std::string& identityToken = "",
bool isModuleAbilityHookEnd = false,
bool isBlockSubwindow = false);
};
Session 创建的典型流程:
1. 应用启动(Ability 启动)
→ Ability Runner 请求 SceneBoard 创建 Session
2. SceneBoard 创建 MainSession
→ 分配 persistentId
→ 创建 RSSurfaceNode(渲染 surface)
→ 返回 ISession 接口给应用
3. 应用创建 WindowSessionImpl
→ 绑定 ISession → WindowEventChannel
→ 通过 Session 通信(非 WMS)
4. 窗口显示
→ 应用调用 Show()
→ SessionManager 通知 SceneBoard
→ SceneBoard 更新窗口布局和可见性
Session 架构的关键优势:
| 优势 | 说明 |
|---|---|
| 生命周期解耦 | 窗口的生命周期由 SceneBoard 统一管理,而非每个应用的 WMS 请求 |
| 灵活布局 | SceneBoard 可以自由控制窗口位置/大小/动画,无需 WMS 参与 |
| 跨进程协作 | Session 接口天然支持多进程交互 |
| 动画同步 | 窗口切换动画在 SceneBoard 侧协调,避免闪现 |
| 扩展性好 | 新窗口类型只需添加新的 Session 子类 |
9. 窗口与 VSync 信号的关系
VSync(垂直同步信号)是渲染的触发源,窗口通过 VsyncStation 实现逐窗口粒度的 VSync 订阅、帧率控制和生命周期管理。
9.1 VsyncStation:窗口级的 VSync 订阅器
每个窗口在创建时生成一个 VsyncStation 实例,绑定到窗口的 RSSurfaceNode:
// window_impl.cpp:131(WindowImpl 构造函数)
WindowImpl::WindowImpl(const sptr<WindowOption>& option) {
// ...
surfaceNode_ = CreateSurfaceNode(property_->GetWindowName(), option->GetWindowType());
if (surfaceNode_ != nullptr) {
vsyncStation_ = std::make_shared<VsyncStation>(surfaceNode_->GetId());
// ↑ 以渲染节点 ID 作为 VSync 订阅的唯一标识
}
}
VsyncStation(定义在 utils/include/vsync_station.h)封装了 VSync 的完整生命周期:
class VsyncStation {
void RequestVsync(const std::shared_ptr<VsyncCallback>& vsyncCallback);
bool IsVsyncReceiverCreated();
void RunOnceOnNextVsync(OnCallback&& callback);
void RunOnceAfterNVsyncs(uint32_t delayVsyncCount, OnCallback&& callback);
int64_t GetVSyncPeriod();
std::optional<uint32_t> GetFps();
void Destroy(); // 窗口销毁时调用
};
9.2 VSync 请求的全链路
窗口需要渲染下一帧
│
├── WindowImpl::RequestVsync(callback) ← Window 接口
│ └── vsyncStation_->RequestVsync(callback)
│
├── 或 SceneSession::RunOnNextVsync(callback) ← SceneBoard 接口
│ └── vsyncStation_->RunOnceOnNextVsync(callback)
│ ↓
│ VsyncStation::RequestVsync()
│ ↓
│ GetOrCreateVsyncReceiver() ← 懒创建,首次使用才初始化
│ ↓
│ RSInterfaces::CreateVSyncReceiver(
│ name, ← "WM_" + pid(进程唯一标识)
│ frameRateLinkerId, ← 帧率链接器(逐窗口帧率控制)
│ vsyncHandler, ← 事件处理器(回调线程)
│ nodeId=surfaceNode_->GetId() ← 窗口的渲染节点 ID
│ )
│ ↓
│ 向 render_service 的 appVSyncDistributor 注册
│ ↓
│ VSync 信号到达 → 回调触发 → 窗口开始新一帧的渲染
关键实现细节(vsync_station.cpp):
// vsync_station.cpp:90
std::shared_ptr<VSyncReceiver> VsyncStation::GetOrCreateVsyncReceiverLocked()
{
if (receiver_ == nullptr) {
auto& rsClient = RSInterfaces::GetInstance();
// 通过 RS 接口创建 VSyncReceiver,传入 nodeId_ 作为窗口标识
auto receiver = rsClient.CreateVSyncReceiver(
"WM_" + std::to_string(::getprocpid()),
frameRateLinker_->GetId(),
vsyncHandler_, nodeId_);
receiver_ = receiver;
}
return receiver_;
}
9.3 窗口级帧率控制
VsyncStation 内部通过 RSFrameRateLinker 绑定到 surfaceNodeId,允许逐窗口设定帧率:
窗口 A (前台动画 60fps) 窗口 B (后台暂停) 窗口 C (视频 24fps)
│ │ │
│ RequestVsync(every frame)│ (no request) │ RequestVsync(24fps)
▼ ▼ ▼
appVSyncDistributor (不注册) (帧率链接器限制)
│ │ │
VSync 每帧到达 零功耗 VSync 1/24s 到达
│ │ │
开始渲染 不渲染 按视频帧率更新
9.4 窗口生命周期与 VSync 的联动
窗口进入后台时停止 VSync 请求,前台时恢复:
// window_impl.cpp:1456
WMError WindowImpl::WindowCreateCheck(uint32_t parentId)
{
if (vsyncStation_ == nullptr || !vsyncStation_->IsVsyncReceiverCreated()) {
return WMError::WM_ERROR_NULLPTR;
}
// ...
}
// window_impl.cpp:1764
void WindowImpl::ClearVsyncStation()
{
if (vsyncStation_ != nullptr) {
vsyncStation_->Destroy(); // 窗口销毁,取消 VSync 注册
}
}
9.5 Session 架构中的 VSync
Session 架构有等价的机制,通过 SceneSession 暴露 VSync 能力:
// scene_session.cpp:10659
void SceneSession::SetVsyncStation(const std::shared_ptr<VsyncStation>& vsyncStation)
{
vsyncStation_ = vsyncStation;
}
void SceneSession::RunOnNextVsync(OnCallback&& callback)
{
RETURN_IF_NULL(vsyncStation_);
vsyncStation_->RunOnceOnNextVsync(std::move(callback));
}
std::optional<uint32_t> SceneSession::GetFpsFromVsync() const
{
RETURN_IF_NULL(vsyncStation_, std::nullopt);
return vsyncStation_->GetFps();
}
9.6 完整的窗口 → 渲染通路
┌─────────────────────────────────┐
│ WindowImpl │
│ ├── surfaceNode_ (渲染出口) │
│ │ ↓ RSSurfaceNode │
│ │ → BufferQueue → render_svc│
│ └── vsyncStation_ (VSync入口) │
│ ↓ VsyncStation │
│ → VSyncReceiver │
│ → appVSyncDistributor │
└──────────┬──────────────────────┘
│
┌────────────┴────────────┐
│ │
RequestVsync() BufferQueue (像素)
│ │
▼ ▼
appVSyncDistributor render_service 主线程
│ ConsumeBuffer
VSync 回调触发 │
│ Prepare/Process
窗口开始新帧 │
(UI树→布局→Canvas) Render Thread
│ GPU/HWC Compo
提交 Transaction │
+ QueueBuffer HDI→Display
关键结论:
| 维度 | 说明 |
|---|---|
| VSync 是全局的还是窗口级别的? | render_service 的 VSync 硬件信号是全局的,但 订阅是窗口级别的 |
| 每个窗口是否都收到同一个 VSync? | 不是。只有 主动 RequestVsync 的窗口 会收到信号,后台窗口收不到 |
| VSync 频率可以逐窗口不同? | 可以。通过 RSFrameRateLinker + VsyncStation 实现逐窗口帧率控制 |
| 窗口如何关联 VSync? | 窗口的 surfaceNode_->GetId() 作为 VSyncReceiver 的识别 ID |
| 窗口销毁时? | ClearVsyncStation() → vsyncStation_->Destroy() → 取消 VSync 注册 |
10. 与 Android 对比
| 维度 | OHOS (Rosen WindowManager) | Android (WindowManager + WMS + SF) |
|---|---|---|
| 服务端 | WindowManagerService(单进程中处理所有窗口操作) | WindowManagerService(SystemServer 中的一个服务) |
| 客户端 API | Window::Create() / WindowManager |
WindowManager.addView() / WindowManagerGlobal |
| 窗口节点 | WindowNode + WindowProperty | WindowState + WindowManager.LayoutParams |
| 窗口树 | WindowNodeContainer(每显示器一个) | DisplayContent(每显示器一个,管理 WindowToken→WindowState) |
| 窗口类型 | 枚举值分三段(BELOW_APP/ABOVE_APP/SUB) | TYPE_APPLICATION / TYPE_SYSTEM / TYPE_SUB 等 |
| Z-Order | WindowZorderPolicy(类型优先级+创建顺序) | WindowManagerPolicy(窗口类型层级 + Z-order 计算) |
| 焦点 | WindowNodeContainer::SetFocusWindow | DisplayContent::setFocusedApp / WindowState 焦点链 |
| 分屏布局 | WindowLayoutPolicy (Cascade / Tile) | SplitScreenTaskOrganizer / TaskOrganizer |
| 安全区域 | AvoidAreaController(状态栏/导航栏/挖孔屏) | InsetsController / SystemInsets |
| 启动窗口 | StartingWindow(专用 WindowNode) | StartingWindow(窗口令牌关联) |
| 桌面集成 | SceneBoard → Session 架构(可选) | Launcher(独立进程,非窗口管理核心) |
| 渲染绑定 | RSSurfaceNode(Render Service Client) | SurfaceControl(SurfaceFlinger) |
| IPC 协议 | 自定义 MessageParcel / Binder | Binder(IWindowManager.aidl) |
| 输入法窗口 | KeyboardSession(Session 架构) | InputMethodManager + InputWindow |
| 多屏支持 | WindowRoot 管理多显示器的 WindowNodeContainer | DisplayManagerService + DisplayContent |
| 动画框架 | RemoteAnimation 控制器 | WindowAnimationSpec / RemoteAnimation |
架构差异总结:
| 核心差异 | OHOS | Android |
|---|---|---|
| 窗口树管理 | WindowRoot → WindowNodeContainer → WindowNode 三层 |
DisplayContent → WindowToken → WindowState 三层 |
| 渲染层耦合 | WMS 直接持有 RSSurfaceNode(与 RenderService 紧耦合) |
WMS 通过 SurfaceControl 间接操作,SurfaceFlinger 独立管理 |
| 窗口类型体系 | 数值分段法(每段留扩展空间) | 属性枚举法(不同类型的 FLAG 和 TYPE 组合) |
| 桌面窗口管理 | 可选方案:经典 WMS 或 SceneBoard Session | 固定方案(Launcher 作为普通应用) |
| 安全区域 | 通过 AvoidAreaController 计算 | 通过 InsetsController + WindowInsets 计算 |
| 窗口生命周期 | WindowNodeStateMachine 严格状态机 | WindowState 内部状态更简化 |
11. 关键技术点
11.1 窗口 ID 生成
WindowController::GenWindowId() 使用原子递增计数器生成唯一窗口 ID,确保同一进程中每个窗口的 ID 唯一。
11.2 窗口属性序列化
WindowProperty 实现 Parcelable 接口,通过 Marshalling/Unmarshalling 在客户端和服务端之间通过 IPC 传递窗口属性。
11.3 窗口死亡通知
WindowRoot 通过 AddDeathRecipient() 注册 DeathRecipient 监控窗口的 IPC 连接。当窗口所在进程异常退出时,自动触发 WindowRoot::DestroyWindow() 清理对应的窗口节点。
11.4 两种 WindowSessionType
WindowOption::SetWindowSessionType() 允许客户端选择使用经典 WMS 模式还是 Session 模式:
| SessionType | 含义 | 适用场景 |
|---|---|---|
| TYPE_DEFAULT | 经典 WMS 模式 | 传统应用 / 无 SceneBoard 环境 |
| TYPE_SCENE_BOARD | SceneBoard Session 模式 | SceneBoard 桌面环境 |
11.5 窗口 flag 系统
WindowFlag 枚举提供窗口行为控制:
| Flag | 含义 |
|---|---|
| WINDOW_FLAG_NEED_AVOID_AREA | 需要计算安全区域 |
| WINDOW_FLAG_PARENT_LIMIT | 限制在父窗口范围内 |
| WINDOW_FLAG_SHOW_WHEN_LOCKED | 锁屏时仍然显示 |
| WINDOW_FLAG_WATER_MARK | 水印窗口 |
| WINDOW_FLAG_HANDWRITE | 手写窗口 |
11.6 窗口与 Node 的两层关系
OHOS 中有两层 Node,分别属于渲染系统和窗口管理系统,容易混淆:
层一:RSSurfaceNode(渲染节点)— 每个窗口一个
WindowImpl 构造函数 → surfaceNode_ = CreateSurfaceNode(name, type)
↓
CreateSurfaceNode() (window_impl.cpp:192)
├── 根据 WindowType 选择 RSSurfaceNodeType
│ ├── APP_MAIN_WINDOW → APP_WINDOW_NODE
│ ├── BOOT_ANIMATION → SELF_DRAWING_WINDOW_NODE
│ ├── PIP / MEDIA → APP_WINDOW_NODE
│ └── 其他 → DEFAULT
│
└── RSSurfaceNode::Create(config, rsSurfaceNodeType)
→ 创建渲染表面(render_service 可见的渲染实体)
RSSurfaceNode 与窗口的 1:1 关系:
- 窗口位置变化 →
surfaceNode_->SetBounds() - 窗口可见性变化 →
surfaceNode_->SetVisible() - 窗口 Canvas 绘制 → 通过 surfaceNode 的 BufferQueue 传输像素
surfaceNode_->GetId()可反向查找到WindowNode
层二:WindowNode(服务端窗口节点)— WMS 端的逻辑节点
WindowController::CreateWindow()
│
├── node = new WindowNode(property, window, surfaceNode, pid, uid)
│ ├── surfaceNode_ → 客户端的 RSSurfaceNode(同一指针)
│ ├── windowToken_ → 客户端 IWindow 回调接口
│ ├── property_ → 窗口属性(类型/模式/矩形)
│ └── abilityToken_ → Ability 令牌(关联启动窗口)
│
├── windowRoot_->SaveWindow(node)
│ └── surfaceIdWindowNodeMap_[surfaceNode->GetId()] = node
│ → 可通过 RS 节点 ID 反向查找到 WindowNode
│
└── windowRoot_->AddWindowNode(parentId, node)
→ 插入 WindowNodeContainer 的 Z-order 树
三层 Node 的全链路关系:
渲染管线 (Rosen) 窗口管理 (WMS) 显示
RSSurfaceNode (渲染) ←→ WindowNode (逻辑) → WindowNodeContainer → Display
↑ ↑
│ surfaceNodeId 映射 │ displayId
│ │
surfaceIdWindowNodeMap_ WindowProperty::displayId
数量关系:
Display 1 个 → WindowNodeContainer 1 个
WindowNodeContainer 1 个 → WindowNode N 个
WindowNode 1 个 → RSSurfaceNode 1 个(1:1)
WindowImpl 1 个 → RSSurfaceNode 1 个(1:1)
RSSurfaceNode 1 个 → render_service 中 1 个渲染表面
Node 类型汇总:
| 维度 | RSSurfaceNode | WindowNode |
|---|---|---|
| 所属系统 | Render Service (Rosen) | Window Manager (WMS) |
| 创建时机 | WindowImpl 构造时 | WMS::CreateWindow() 时 |
| 职责 | 渲染表面、BufferQueue、VSync 绑定 | 窗口逻辑(属性/焦点/Z-Order/生命周期) |
| 跨进程 | 同一指针跨进程引用 | 服务端独有 |
| 销毁 | WindowImpl 析构 | WMS::DestroyWindow() |
11.7 窗口的渲染绑定
每个 WindowImpl 创建时自动创建 RSSurfaceNode(Render Service 渲染节点):
// WindowImpl 构造函数(window_impl.cpp:131)
WindowImpl::WindowImpl(const sptr<WindowOption>& option) {
// 创建 RS 渲染 Surface
struct RSSurfaceNodeConfig config;
config.SurfaceNodeName = name_;
surfaceNode_ = RSSurfaceNode::Create(config, RSSurfaceNodeType::DEFAULT);
// 设置窗口 ID 到渲染节点
surfaceNode_->SetWindowId(property_->GetWindowId());
}
RSSurfaceNode 是 OHOS 渲染管线(Rosen)中的基础节点,绑定到窗口后:
- 窗口的位置/大小变化 → 对应 RSSurfaceNode 的 bounds 变化
- 窗口可见性变化 → RSSurfaceNode 的 visible 标志变化
- 窗口的 Canvas 绘制结果 → 通过 BufferQueue 传递到 render_service
11.8 启动窗口(StartingWindow)
StartingWindow 是应用冷启动/热启动时显示的临时窗口,由 WMS 在应用准备好之前创建:
// starting_window.h
class StartingWindow {
void Show(sptr<WindowTransitionInfo> info,
std::shared_ptr<Media::PixelMap> pixelMap,
uint32_t bkgColor, bool isColdStart);
void Cancel(sptr<IRemoteObject> abilityToken);
};
| 启动类型 | 触发条件 | 处理方式 |
|---|---|---|
| 冷启动 | 应用进程未运行 | 显示像素图/背景色类型的 StartingWindow |
| 热启动 | 应用进程已运行但窗口不可见 | 可能复用已有的窗口快照 |
| 应用闪屏 | 应用自定义启动页 | StartingWindow 显示后,应用接管界面 |
StartingWindow 通过 WindowController::StartingWindow() 创建并添加为临时窗口节点,在应用实际窗口准备好后被 CancelStartingWindow() 移除。
11.9 窗口创建权限检查
WindowManagerService::CreateWindow() 在创建窗口前执行两重权限检查:
// 1. 系统窗口权限检查
if (WindowHelper::IsSystemWindow(property->GetWindowType())) {
if (!Permission::IsSystemCalling()) {
return WMError::WM_ERROR_INVALID_TYPE;
}
}
// 2. 录音/悬浮窗权限检查(特定类型需要额外权限)
if (property->GetWindowType() == WindowType::WINDOW_TYPE_FLOAT) {
if (!Permission::IsSystemSetting()) {
return WMError::WM_ERROR_NOT_SYSTEM_APP;
}
}
11.10 VsyncStation:窗口级 VSync 机制
VsyncStation 是连接窗口管理子系统和渲染子系统的关键桥梁,已在第 9 章详细展开。此处总结其核心机制:
| 机制 | 说明 |
|---|---|
| 创建时机 | WindowImpl 构造时,绑定到 surfaceNode_->GetId() |
| 懒加载 | VSyncReceiver 在首次 RequestVsync() 时创建 |
| 帧率控制 | 通过 RSFrameRateLinker 实现逐窗口帧率设定 |
| 生命周期 | 窗口销毁时 ClearVsyncStation() → Destroy() 取消注册 |
| Session 等价 | SceneSession::SetVsyncStation() + RunOnNextVsync() |

浙公网安备 33010602011771号