引言
在Android中,独立窗口自绘渲染,典型应用场景比如SurfaceView与手机双边侧滑返回动画面板(WMS.addView)。最近入职一家新公司,涉及对接更底层渲染实现,具体表现在NDK层,获取一个独立Window窗口,上层用Skia进行绘制,并在Android系统中渲染出来。本文旨在分析WMS.addView链路,明淅渲染关键路径,为后面自定义渲染作支持。
核心类说明
在 Android 系统中,独立窗口自绘渲染,绕不开Surface 和 ANativeWindow ,二者是与图形渲染和窗口管理相关的核心类,它们的关系和功能可以总结如下:
类结构解释
1 | class Surface : public ANativeObjectBase<ANativeWindow, Surface, RefBase>{ |
- 继承关系:
Surface继承自模板类ANativeObjectBase<ANativeWindow, Surface, RefBase>。 - 模板参数含义:
ANativeWindow:表示底层的原生窗口接口。Surface:子类自身(使用 CRTP 模式,允许基类调用子类方法)。RefBase:Android 的引用计数基类,用于对象生命周期管理。
Surface 的作用
- 图形渲染的抽象层:
Surface是 Android 应用与显示系统之间的桥梁,代表一个可绘制的表面。应用程序通过Surface进行 UI 渲染(例如通过 Canvas 或 OpenGL ES)。 - 跨进程通信:
Surface实现了Parcelable接口,可跨进程传递(如从应用进程传递到 SurfaceFlinger 服务进程)。 - 缓冲区管理:
管理图形缓冲区队列(BufferQueue),协调生产者和消费者(如应用和 SurfaceFlinger)之间的缓冲区交换。
ANativeWindow 的作用
- 原生窗口的 C 接口:
ANativeWindow是 Android NDK 中定义的抽象,提供对底层窗口系统的访问(如通过ANativeWindow_fromSurface()获取)。 - 跨平台兼容性:
封装了不同硬件/平台的窗口操作(例如设置缓冲区大小、格式,提交渲染结果)。 - 与 Surface 的关系:
ANativeWindow是Surface的底层接口,Surface类通过继承ANativeObjectBase实现了ANativeWindow的功能。
两者关系
- 继承与封装:
Surface是ANativeWindow的高层封装,提供更易用的 C++ API,而ANativeWindow是底层的 C 风格接口。 - 功能实现:
Surface通过ANativeObjectBase模板类继承ANativeWindow的接口,并实现其方法(如dequeueBuffer/queueBuffer),最终通过RefBase管理生命周期。 - 使用场景:
- Java/Kotlin 层:通过
Surface类进行 UI 渲染。 - Native 层(NDK):通过
ANativeWindow直接操作窗口(例如 Vulkan/OpenGL ES 渲染)。
- Java/Kotlin 层:通过
总结
ANativeWindow:底层原生窗口接口,提供跨平台的窗口操作(NDK 使用)。Surface:高层封装,整合ANativeWindow功能并提供 Android 框架级的渲染管理。- 关系:
Surface是ANativeWindow的面向对象实现,二者共同服务于图形渲染,前者用于 Java/C++ 框架层,后者用于更接近硬件的 NDK 层。
WMS.addView自绘链路
在Android 10及以后,WMS.addView可以以侧滑返回动画面板实现代码作说明,代码主要在systemui/navigationbar/gestural,核心类EdgeBackGestureHandler、BackPanelController、BackPanel,这三个组件共同构成了 Android 的边缘返回手势系统,提供流畅的用户体验,是一个WMS.addView应用场景。
其中ViewCaptureAwareWindowManager以一个独立的Window添加BackPanel(View),BackPanel响应相应滑动事件,用Canvas做自绘实现,具体链路包括:
BackPanelController#setLayoutParams
1 | //SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler |
layoutParams来自EdgeBackGestureHandler#createLayoutParams
1 | //SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler |
WindowManager.addView 绑定Window
WindowManager.addView与WMS处理Window绑定。
- WindowManager.addView 调用链:
1 | // frameworks/base/core/java/android/view/WindowManagerImpl.java |
- WindowManagerGlobal 中的处理:
1 | // frameworks/base/core/java/android/view/WindowManagerGlobal.java |
ViewRootImpl.setView()触发窗口创建
在setView()中,通过 IPC 调用WindowManagerService创建窗口:
1 | // ViewRootImpl.java |
mWindowSession是IWindowSession的实例,由WindowManagerGlobal创建,是 App 进程与 WMS 通信的代理。addToDisplayAsUser是 IPC 调用,通知 WMS 创建窗口并分配资源。
在 WMS 服务端,Session.addToDisplayAsUser() 最终会创建 WindowState:
1 | // WindowManagerService.java |
WindowState是 WMS 中窗口的抽象,管理窗口的层级、可见性等。
ViewRootImpl.relayoutWindow 绑定Surface
SurfaceControl 的创建实际发生在 窗口的首次布局(performTraversals)阶段,由 WindowManagerService 触发。关键流程如下:
在客户端(应用进程)的 ViewRootImpl 中,通过 IPC 调用 WindowManagerService 的 relayoutWindow 方法,请求更新窗口布局并创建 Surface:
1 | // frameworks/base/core/java/android/view/ViewRootImpl.java |
在服务端(WindowManagerService),mWindowSession.relayout 最终会调用 WindowStateAnimator.createSurfaceLocked() 创建 SurfaceControl:
1 | //frameworks/base/services/core/java/com/android/server/wm/Session.java |
视图通过 Surface 绘制内容
在 ViewRootImpl 的绘制流程中,通过 Surface 提交帧数据:
1 | // ViewRootImpl.java -> performTraversals() |
surface.lockCanvas()获取Canvas对象,用于绘制。unlockCanvasAndPost()提交绘制内容到Surface,最终由 SurfaceFlinger 合成显示。
总结流程
addView触发ViewRootImpl.setView()
客户端通过 IPC 调用WMS.addWindow(),创建WindowState。首次布局请求
ViewRootImpl.relayoutWindow()调用WMS.relayoutWindow(),触发SurfaceControl的创建。SurfaceControl的创建
服务端通过SurfaceSession创建SurfaceControl,并通过 Binder 将句柄返回客户端。客户端
Surface绑定
客户端ViewRootImpl通过updateBlastSurfaceIfNeeded将Surface与SurfaceControl绑定。绘制提交
客户端通过Surface.lockCanvas()和unlockCanvasAndPost()将内容绘制到Surface,由 SurfaceFlinger 合成显示。
关键绑定关系总结
| 组件 | 作用 |
|---|---|
ViewRootImpl |
连接视图系统与 WMS,管理 Surface 生命周期和绘制流程。 |
WindowState |
WMS 中的窗口抽象,持有 SurfaceControl 控制 Surface 属性。 |
SurfaceControl |
服务端(WMS)对 Surface 的控制句柄,管理缓冲区分配和属性,对应 SurfaceFlinger 的 Layer。 |
Surface |
客户端(应用进程)的绘制接口,通过 Binder 持有服务端 SurfaceControl 的引用。 |
流程总结
窗口创建
addView触发ViewRootImpl创建,并通过 IPC 调用 WMS 的addToDisplayAsUser,在服务端生成WindowState和SurfaceControl。Surface 分配
WMS 通过SurfaceControl创建Surface,并将句柄传递给应用进程的ViewRootImpl。绘制绑定
ViewRootImpl通过relayoutWindow更新Surface,在performTraversals中完成视图的测量、布局、绘制,最终通过Surface提交帧数据。显示合成
SurfaceFlinger 根据Surface的缓冲区内容,合成到屏幕。