07.WMS机制深入分析
目录介绍
- 01.快速了解WMS机制
- 1.1 WMS是什么
- 1.2 应用于那些场景
- 1.3 WMS主要功能
- 1.4 Window是什么
- 1.5 WMS整体框架
- 02.WMS核心流程
- 2.1 WMS启动流程
- 03.WMS流程分析
- 3.1 Window添加View
- 3.2 WMS核心职责
- 3.3 WMS是如何启动
- 3.4 WMS构造方法
- 3.5 WMS窗口管理
- 05.一些源码分析
- 5.1 addView源码分析
- 5.2 remove源码与解析
01.快速了解WMS机制
1.1 WMS是什么
- 开发中各种UI显示异常的bug都可以在WMS体系中找到对应的解决办法和对应原理。
- 因为WMS管理着所有的窗口,包括创建、删除和修改,以及将某个窗口设置为焦点窗口。
- WMS(WindowManagerService)相关概念
- Window:它是一个抽象类,具体实现类为 PhoneWindow ,它对 View 进行管理。Window是View的容器,View是Window的具体表现内容;
- WindowManager:是一个接口类,继承自接口 ViewManager ,从它的名称就知道它是用来管理 Window 的,它的实现类为 WindowManagerImpl;
- WMS:是窗口的管理者,它负责窗口的启动、添加和删除。另外窗口的大小和层级也是由它进行管理的;
1.2 应用于那些场景
- Activity页面渲染
- Activity 启动后就可以看到我们写的 Layout 布局界面,Activity 从 setContentView() 加载布局到Window上,这个过程就涉及到WMS。
- Dialog弹窗渲染
- 创建Dialog后,会去创建Window窗口,然后通过addView形式将视图添加到窗口上。这个过程就涉及到WMS。
- 可以解决那些问题
- 如果你的定位是做界面开发,那么界面怎么来的?如何显示的?如何布局?如何渲染……要明白这些问题,WMS就是你必须掌握的内容。
1.3 WMS主要功能
- 主要功能
- Surface管理。为所有窗口分配Surface,客户端向WMS添加一个窗口的过程,其实就是WMS为其分配一块Surface的过程,一块块Surface在WMS的管理下有序的排布在屏幕上。Window的本质就是Surface。
- 管理窗口的显示顺序、尺寸、位置, 最终都会反馈SurfaceFlinger。
- 窗口动画, 包括进入,退出动画
- 输入系统中转站:WMS是派发系统按键和触摸消息的最佳人选,当接收到一个触摸事件,它需要寻找一个最合适的窗口来处理消息,而WMS是窗口的管理者,系统中所有的窗口状态和信息都在其掌握之中,完成这一工作不在话下。
- 主要功能图
image
1.4 Window是什么
- Window是什么?
- 表示一个窗口的概念,是所有View的直接管理者,任何视图都通过Window呈现(点击事件由Window->DecorView->View; Activity的setContentView底层通过Window完成)
- Window是一个抽象类,具体实现是PhoneWindow。这个可以看Activity#attach方法源码
- 创建Window需要通过WindowManager创建,WindowManager是外界访问Window的入口,Window具体实现位于WindowManagerService中
- WindowManager和WindowManagerService的交互是通过IPC完成
- Window和View关系
- Window和View通过ViewRootImpl建立联系,iew是视图的呈现方式,但是不能单独存在,必须依附在Window这个抽象的概念上。
- WMS把所有的用户消息发给View/ViewGroup,但是在View/ViewGroup处理消息的过程中,有一些操作是公共的, Window把这些公共行为抽象出来, 这就是Window。
- Activity、View、Window三者之间的关系
- 在Activity启动过程其中的attach()方法中初始化了PhoneWindow,而PhoneWindow是Window的唯一实现类。
- 然后Activity通过setContentView将View设置到了PhoneWindow上,而View通过WindowManager的addView()、removeView()、updateViewLayout()对View进行管理。
1.5 WMS整体框架
- WMS整体框架
image
- WMS简单类图
image
02.WMS核心流程
2.1 WMS启动流程
- WMS启动流程
image
03.WMS流程分析
3.1 Window添加View
- 先看一个简单的案例。在主屏幕上添加一个TextView并展示,并且这个TextView独占一个窗口。
TextView mview = new TextView(context); WindowManager mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams(); wmParams.type = WindowManager.LayoutParams.TYPE_TOAST; wmParams.width = 800; wmParams.height = 800; mWindowManager.addView(mview, wmParams);
- 对Window添加View的流程步骤分析
- WindowManager.addView添加窗口之前,TextView的onDraw不会被调用,也就说View必须被添加到窗口中,才会被绘制。只有申请了依附窗口,View才会有可以绘制的目标内存。
- 当APP通过WindowManagerService的代理向其添加窗口的时候,WindowManagerService除了自己进行登记整理,还需要向SurfaceFlinger服务申请一块Surface画布,其实主要是画布背后所对应的一块内存,只有这一块内存申请成功之后,APP端才有绘图的目标,并且这块内存是APP端同SurfaceFlinger服务端共享的,这就省去了绘图资源的拷贝。
- APP端是可以通过unLockCanvasAndPost直接同SurfaceFlinger通信进行重绘的,就是说图形的绘制同WMS没有关系,WMS只是负责窗口的管理,并不负责窗口的绘制。
3.2 WMS核心职责
- 窗口管理:
- WMS是窗口的管理者,负责窗口的启动,添加和删除,另外窗口的大小也时有 WMS 管理的,管理窗口的核心成员有 DisplayContent,WindowToken 和 WindowState
- 窗口动画:
- 窗口间进行切换时,使用窗口动画可以更好看一些,窗口动画由 WMS 动画子系统来负责,动画的管理系统为 WindowAnimator
- 输入系统的中转站:
- 通过对窗口触摸而产生的触摸事件,InputManagerServer(IMS) 会对触摸事件进行处理,他会寻找一个最合适的窗口来处理触摸反馈信息,WMS 是窗口的管理者,因此理所当然的就成为了输入系统的中转站。
- Surface管理:
- 窗口并不具备绘制的功能,因此每个窗口都需要有一个块 Surface 来供自己绘制,为每个窗口分配 Surface 是由 WMS 来完成的。
3.3 WMS是如何启动
- WMS 是在 SystemServer 内部启动的
- Android 系统在启动的时候,会启动两个重要的进程,一个是 Aygote 进程,两一个是由 Zygote 进程 fork 出来的 system_server 进程,SystemServer 会启动我们在系统中所需要的一系列 Service。
- 在SystemServer#startOtherServices方法中
- 核心1:SystemServer#WindowManagerService.main,传入了 IMS,因为 WMS 是 IMS 的中转站。观察 WindowManagerService.main 方法可以知道他是运行在 SystemServer 的 run 方法中,换句话说就是运行在 system_server 线程中。
- 核心2:SystemServer#ServiceManager.addService,将 WMS 和 IMS 注册到 ServerManager 里面,这样客户端想要使用 WMS 就需要先去 ServiceManager 中查询信息,然后与 WMS 所在的进程建立通信,这样客户端就可以使用 WMS 。
3.4 WMS构造方法
- 在WindowManagerService#main方法中
- 通过 DisplayThread 的 getHandler 方法获取到了 DisplayThread 的 Handler 实例。用来处理需要低延时显示的相关操作,runWithScissors 表达式中创建了 WMS 对象。
- 在WindowManagerService#WindowManagerService()构造方法中
- 初始化 WindowManagerPolicy ,它用来定义一个窗口测量所需要遵循的规范。
- 创建了 WindowAnimator,它用于管理所有的窗口动画。
- 创建 RootWindowContainer 对象,根窗口容器。
- 获取 DisplayManager 服务。
- 获取 AMS,并持有他的引用。
- WMS的启动中WMS创建完成后会调用 wm.onInitReady 方法
- 和 WMS 的 main 方法类似,WindowManagerPolicy (简称 WMP) 是一个接口,init 的具体实现在 PhoneWindowManager(PWM) 中
- init 方法运行在 android.ui线程中。因此他的线程优先级要高于 android.display 线程,必须等 init 方法执行完成后,android.display线程才会被唤醒从而继续执行下面的代码。
3.5 WMS窗口管理
- Window 的操作有两大部分,一部分是 WindowManager 来处理,一部分是 WMS 来处理
- 先看第一部分WindowManager处理逻辑
- WindowManager 中,通过 WindowManagerGlobal 创建 ViewRootImpl ,也就是 View 的根。
- 在 ViewRootImpl 中完成对 View 的绘制等操作,然后通过 IPC 获取到 Session,最终通过 WMS 来进行处理。
- 再看第二部分WMS处理逻辑
- 主要分析是ViewRootImpl#setView()到WindowManagerService.addWindow()的这个过程,涉及到跨进程通信。
- 1.ViewRootImpl#setView()过程。mWindowSession是IWindowSession对象。在创建ViewRootImpl对象时被实例化。
- 2.WindowManagerGlobal#getWindowSession()过程。getWindowManagerService()通过AIDL返回WindowManagerService实例。之后调用WindowManagerService#openSession()。
- 3.WindowManagerService#openSession()过程。返回一个Session对象。也就是说在ViewRootImpl#setView()中调用的是mWindowSession.addToDisplay,其实就是Session#addToDisplay()。
- 4.Session#addToDisplay()过程。mService是个WindowManagerService对象,也就是说最后调用的是WindowManagerService#addWindow()
- 5.WindowManagerService#addWindow()过程。mWindowMap是个Map实例,将WindowManager添加进WindowManagerService统一管理。至此,整个添加视图操作解析完毕。
- 注意WMS并不关心View的具体内容
- WMS只关心各个应用显示的界面大小,层级值等,这些数据到包含在 WindowManager.LayoutParams 中。
05.一些源码分析
5.1 addView源码分析
- Window的addView源码分析?
- WindowManager是一个接口,真正实现类是WindowManagerImpl,并最终以代理模式交给WindowManagerGlobal实现。
- addView: 1-创建ViewRootImpl;2-将ViewRoot、DecorView、布局参数保存到WM的内部列表中;3-ViewRoot.setView()建立ViewRoot和DecorView的联系。
- setView:1-进行View绘制三大流程;2-会通过WindowSession完成Window的添加过程(一次IPC调用)
- requestLayout:内部调用scheduleTraversals(), 底层通过mChoreographer去监听下一帧的刷新信号。
- mWindowSession.addToDisplay: 执行WindowManagerService的addWindow
- addWindow: 检查参数等设置;检查Token;将Token、Window保存到WMS中;将WindowState保存到Session中。
5.2 remove源码与解析
- Window的remove源码与解析
- WindowManager中提供了两种删除接口:removeView异步删除、removeViewImmediate同步删除(不建议使用)
- 调用WMGlobal的removeView
- 调用到WMGlobal的removeViewLocked进行真正的移除
- 执行ViewRoot的die方法(): 1-同步方法直接调用doDie 2-异步方法直接发送Message
- doDie(): 调用dispatchDetachedFromWindow()和WindowManagerGlobal.getInstance().doRemoveView(this)
- dispatchDetachedFromWindow:
- 1回调onDetachedFromeWindow;
- 2垃圾回收相关操作;
- 3通过Session的remove()在WMS中删除Window;
- 4通过Choreographer移除监听器
参考博客
- Android开发中的WMS详细解析
- https://mp.weixin.qq.com/s/kanNsdzCv-Gs9ED3t-2mww
- Android WMS工作原理浅析(一)
- https://blog.csdn.net/a734474820/article/details/125602626
- Android WMS流程
- https://copyfuture.com/blogs-details/202112111524292567
- Android | WMS 解析(一)
- https://www.ngui.cc/article/show-640926.html
- Android系统服务-WMS
- https://www.jianshu.com/p/4d34edb6b054