您现在的位置是:首页 > 正文

Android Framework底层原理——WMS机制

2024-02-01 02:08:47阅读 2

快速了解WMS机制

WMS是什么

  • 开发中各种UI显示异常的bug都可以在WMS体系中找到对应的解决办法和对应原理。
    • 因为WMS管理着所有的窗口,包括创建、删除和修改,以及将某个窗口设置为焦点窗口。
  • WMS(WindowManagerService)相关概念
    • Window:它是一个抽象类,具体实现类为 PhoneWindow ,它对 View 进行管理。Window是View的容器,View是Window的具体表现内容;
    • WindowManager:是一个接口类,继承自接口 ViewManager ,从它的名称就知道它是用来管理 Window 的,它的实现类为 WindowManagerImpl;
    • WMS:是窗口的管理者,它负责窗口的启动、添加和删除。另外窗口的大小和层级也是由它进行管理的;

应用于那些场景

  • Activity页面渲染
    • Activity 启动后就可以看到我们写的 Layout 布局界面,Activity 从 setContentView() 加载布局到Window上,这个过程就涉及到WMS。
  • Dialog弹窗渲染
    • 创建Dialog后,会去创建Window窗口,然后通过addView形式将视图添加到窗口上。这个过程就涉及到WMS。
  • 可以解决那些问题
    • 如果你的定位是做界面开发,那么界面怎么来的?如何显示的?如何布局?如何渲染……要明白这些问题,WMS就是你必须掌握的内容。

WMS主要功能

  • 主要功能

    • Surface管理。为所有窗口分配Surface,客户端向WMS添加一个窗口的过程,其实就是WMS为其分配一块Surface的过程,一块块Surface在WMS的管理下有序的排布在屏幕上。Window的本质就是Surface。
    • 管理窗口的显示顺序、尺寸、位置, 最终都会反馈SurfaceFlinger。
    • 窗口动画, 包括进入,退出动画
    • 输入系统中转站:WMS是派发系统按键和触摸消息的最佳人选,当接收到一个触摸事件,它需要寻找一个最合适的窗口来处理消息,而WMS是窗口的管理者,系统中所有的窗口状态和信息都在其掌握之中,完成这一工作不在话下。
  • 主要功能图

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进行管理。

WMS整体框架

  • WMS整体框架

  • WMS简单类图

WMS核心流程

WMS启动流程

  • WMS启动流程

WMS流程分析

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只是负责窗口的管理,并不负责窗口的绘制。

WMS核心职责

  • 窗口管理:
    • WMS是窗口的管理者,负责窗口的启动,添加和删除,另外窗口的大小也时有 WMS 管理的,管理窗口的核心成员有 DisplayContent,WindowToken 和 WindowState
  • 窗口动画:
    • 窗口间进行切换时,使用窗口动画可以更好看一些,窗口动画由 WMS 动画子系统来负责,动画的管理系统为 WindowAnimator
  • 输入系统的中转站:
    • 通过对窗口触摸而产生的触摸事件,InputManagerServer(IMS) 会对触摸事件进行处理,他会寻找一个最合适的窗口来处理触摸反馈信息,WMS 是窗口的管理者,因此理所当然的就成为了输入系统的中转站。
  • Surface管理:
    • 窗口并不具备绘制的功能,因此每个窗口都需要有一个块 Surface 来供自己绘制,为每个窗口分配 Surface 是由 WMS 来完成的。

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 。

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线程才会被唤醒从而继续执行下面的代码。

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 中。

一些源码分析

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中。

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 Framework底层原理手册:https://qr18.cn/AQpN4J

  1. 开机Init 进程
  2. 开机启动 Zygote 进程
  3. 开机启动 SystemServer 进程
  4. Binder 驱动
  5. AMS 的启动过程
  6. PMS 的启动过程
  7. Launcher 的启动过程
  8. Android 四大组件
  9. Android 系统服务 - Input 事件的分发过程
  10. Android 底层渲染 - 屏幕刷新机制源码分析
  11. Android 源码分析实战
  12. ……

网站文章

  • Alan Turing阿兰.图灵---计算机之父/人工智能之父

    提出图灵机理论,二战时破解德国通讯密码,挽救无数生命。提出仿真系统和自动程序设计概念,设计了"图灵测试",有"计算机之父","人工智能之父","破译之父"等美誉。 一、生平1912年6月23日,出生于英国伦敦1931年-1934年,在英国剑桥大学国王学院学习1932年-1935年,研究量子力学,概率论和逻辑学1935年,由于独立发现中心极限定理,获Smith奖,年仅23岁被选为剑桥大学国王

    2024-02-01 02:08:19
  • OpenGL ES 3.0 开发(十九):相机抖音滤镜

    OpenGL ES 3.0 开发(十九):相机抖音滤镜

    该原创文章首发于微信公众号:字节流动 OpenGLES 相机抖音滤镜 最近几篇文章主要是利用 OpenGL 实现相机预览的一些常见的滤镜,上一篇主要介绍了 LUT 滤镜的原理及简单实现方法,而本文主要介绍抖音短视频 App 里面一些常见滤镜的实现,这里只做抛砖引玉,玩滤镜主要靠想象力去实现一些酷炫的效果。 分色偏移 分色偏移滤镜原理:基于原纹理坐标进行偏移,分别采样后再按照 RGBA 通道进...

    2024-02-01 02:08:14
  • 【图片素材】小程序图片

    【图片素材】小程序图片

    iconfont 阿里巴巴矢量图标库iconfont-阿里巴巴矢量图标库https://www.iconfont.cn/

    2024-02-01 02:08:07
  • ansible点对点模块练习

    ping模块[root@S01 ~]# ansible all -m ping192.168.137.129 | SUCCESS => { "changed": false, "ping": "pong"}command模块[root@S01 ~]# ansible web -m command -a 'chdir=/tmp ls'192.168.137...

    2024-02-01 02:07:36
  • 关于MyBatis 一级缓存详解

    关于MyBatis 一级缓存详解

    缓存就是内存中的一个对象,用于对数据库查询结果的保存,用于减少与数据库的交互次数从而降低数据库的压力,进而提高响应速度。MyBatis 中的缓存就是说 MyBatis 在执行一次SQL查询或者SQL更...

    2024-02-01 02:07:30
  • Python如何获取动态加载的数据呢 ?

    Python如何获取动态加载的数据呢 ?

    我们通过requests模块进行数据爬取无法每次都是可见即可得,有些数据是通过非浏览器地址栏中得url请求到的地址。而是其他请求请求到的数据,那么这些通过其他请求请求到的数据就是动态加载的数据。(猜测有可能是js代码当咱们访问此页面时就会发送得get请求,到其他url中获取数据)

    2024-02-01 02:07:23
  • linux安装tensorflow

    linux安装tensorflow

    linux安装tensorflow

    2024-02-01 02:07:18
  • C#中get与set

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace ConsoleApplication16{ class Program { static void Main(...

    2024-02-01 02:06:51
  • JavaScript实现单页面应用程序和浏览器返回按钮的关联

    场景描述:页面中实现整个页面的内容的替换,但是不使用我们常用的页面【跳转】,【跳转】也就不符合单页面的诉求。事实上单页面的内容切换也是和局部的内容切换一样,同样使用页面DOM元素的CSS属性中的【显示】和【隐藏】来控制。但当新的页面没有返回按钮时,就需要和浏览器的按钮实现绑定,则需要用到history对象的pushstate方法和popstate的监听方法。话不多说,来一个简单的案例予以展示。

    2024-02-01 02:06:44
  • JAVA开发(外部接口调用授权问题记录总结)

    JAVA开发(外部接口调用授权问题记录总结)

    现在很多web项目或者小程序在上线后都需要进行交叉引流,交叉业务合作,数据传输,与其他的企业,网站,app合作。那么就需要接口数据调用。那么在做外部系统接口调用和自己开发的微服务间的接口调用显然是不同...

    2024-02-01 02:06:37