8.WindowManagerService简介

WmS是Android中图形用户接口的引擎,它管理着所有窗口,包括创建、删除窗口以及将某个窗口设置为焦点等。

在WmS中,窗口是由两部分内容构成:

  • 描述该窗口的类WindowState。
  • 该窗口在屏幕上对应的界面Surface。

它的功能可以归纳为两个:

  • 保持窗口的层次关系,以便SurfaceFlinger能够据此绘制屏幕
  • 把窗口信息传递给InputManager对象,以便InputDispatcher能够把输入消息派发给和屏幕上显示一致的窗口。

打个比方,就像一出由N个演员参与的话剧:SurfaceFlinger是摄像机,WMS是导演,ViewRoot则是演员个体。摄像机(SurfaceFlinger)的作用是单一而规范的,它负责客观地捕获当前的画面,然后真是的呈现给观众。导演(WMS)则会考虑到话剧的舞台效果和视觉美感,如他需要根据实际情况来安排各个演员的排序站位,谁在前谁在后,都会影响到演出的”画面效果“与”剧情编排“,而各个演员的长相和表情(ViewRoot)则更多的取决于他们自身的条件与努力。正式通过这三者的”各司其职“,才能最终为观众呈现出异常美妙绝伦的”视觉盛宴“。

Android采用层叠式布局,这种布局的特点在于允许多个窗口层叠显示。该布局一般都需要一个窗口管理服务端。从程序设计的角度看,有两种设计模式可以实现服务端:

  • 独立进程方式

    使用一个独立的进程专门用于屏幕的绘制和消息处理,所有的其他应用程序当需要创建窗口时,通过进程通信的方式请求管理服务创建窗口。比如Linux上的X-window就是一种独立进程的方式,它使用Socket通信的方式,通知窗口管理服务进行窗口的创建及交互消息传递。

  • 共享库方式

    使用一段共享程序,该段共享程序中保存了所有客户端的窗口信息,共享库和每个客户端程序都运行于同一个进程之间。Windows操作系统使用的就是这种方式,很多嵌入式系统也使用这种方式。该方式的有点是窗口管理的开销比较小,尤其是窗口的交互,因为它不需要进程间通信,其缺点就是任何一个客户端的不适当操作都可能导致窗口系统崩溃。

在WmS内部逻辑中,会进行三种常见的操作,具体的操作可能会对应不同的函数名称,这三种常见的操作为assign layer、perform layout以及place surface:

  • Assign layer的意思是为窗口分配层值。在WmS中,每个窗口都是用WindowState类来描述,而窗口要在界面上显示时,需要制定窗口的层值。从用户的视角来看,层值越大,其窗口越靠近用户,窗口之间的层叠正式按照层值进行的。
  • perform layout的意思是计算窗口的大小。每个窗口对象都必须有一个大小,即窗口大小,perform layout将根据状态栏大小、输入法窗口的状态、窗口动画状态计算该窗口的大小。
  • place surface的意思是调整Surface对象的属性,并重新将其显示到屏幕上。由于assign layer和perform layout的执行结果影响的仅仅是WindowState中的参数,而能够显示到屏幕上的窗口都包含一个Surface对象,因此只有将以上执行结果的窗口层值、大小设置到Surface对象中,屏幕上才能看出该窗口的变化。place surface的过程就是将这些值赋值给Surface对象,并告诉Surface Flinger服务重新显示这些Surface对象。

WmS接口结构

WmS接口结构是指WmS功能模块与其他模块之间的交互接口,其中主要包括与AmS模块及应用程序客户端的接口。

该结构中的主要交互过程如下:

  • 应用程序在Activity中添加、删除窗口。具体实现就是通过调用WindowManager类的addView()和removeView()函数完成,这会转而调用ViewRoot类的相关方法,然后通过IPC调用到WmS中的相关方法完成添加、删除过程。
  • 当AmS通知ActivityThread销毁某个Activity时,ActivityThread会直接调用WindowManager中的removeView()方法删除窗口。
  • AmS中直接调用WmS,这种调用一般都不是请求WmS创建或删除窗口,而是告诉WmS一些其他信息。

在WmS内部,全权接管了输入消息的处理和屏幕的绘制。其中输入消息的处理是借助于InputManager类完成的。而绘制屏幕则是借助于SurfaceFlinger模块完成的,SurfaceFlinger是Linux的一个驱动,它内部会使用芯片的图形加速引擎完成对界面的绘制。

WindowState

由于WmS是用来管理窗口的,因此需要定义一个专门的类来表示窗口,WmS中表示窗口的类就是WindowState。从设计原理的角度来说,似乎使用WindowState类来表示一个窗口就可以了,但是从程序实现的角度来讲,为了变成的便利性及程序逻辑的清晰性,WmS类内部还定义了两个额外的用来表示窗口的类,分别是WindowToken和AppWindowToken。为什么还需要这两个额外的类?

  • 每个窗口都会对应一个WindowState对象。因为窗口的本质就是由WindowState类描述的数据对象,WindowState类中记录作为一个窗口应该有的全部属性,比如窗口的大小,在屏幕上的层值,以及窗口动画过程的各种状态信息。
  • WindowToken描述的是窗口对应的token的相关属性,每个窗口都会对应一个WindowToken对象,但是一个窗口的所有子窗口将对应同一个WindowToken对象,即多对一的关系。
  • 如果窗口是由Activity创建的,即该窗口对应一个Activity,那么该窗口同时对应一个AppWindowToken对象。

Session

和SurfaceFlinger直接打交道的类本来是SurfaceSession。当应用程序需要创建Surface时,会请求WmS去完成创建的工作,WmS会为每一个应用程序分配一个SurfaceSession对象。然而一个surfaceSession对象不足以表示一个客户端,因此,WmS定义了Session类,它可被认为是SurfaceSession的一个包装。Session对象是当应用程序调用WmS的openSession()函数时创建的,而应用程序又是在ViewRoot类中调用openSession的。

创建窗口

创建窗口的时机可分为两种:

  • 程序员主动调用WindowManager类的addView()方法。
  • 当用户启动一个新的Activity或者显示一个对话框、菜单栏等的时候,在这种情况下,程序员并不是直接调用addView()函数,但是这些类的内部同样会间接调用addView()函数。

  • 客户端调用WindowManager类的addView()方法后,该方法会创建一个新的ViewRoot对象,然后调用ViewRoot类的setView()方法,该方法中会通过IPC方式调用WmS类中内联类Session的add()方法。
  • Session类的add()方法又会间接调用WmS的addWindow()方法,该方法内部又分为三个小过程:
    • 第一个过程是进行前置处理,即首先判断参数的合法性,以确保接下来的添加操作能够顺利进行。
    • 第二个过程是具体添加和窗口相关的数据。
    • 第三个过程是后置处理,即添加窗口会引起相关状态的变化,因此需要把这些变化反应到相关的数据中。

AmS与WmS的交互

AmS和WmS都是窗口管理系统的核心,不过AmS侧重于对Activity的管理,而WmS侧重于对窗口的管理。系统启动后首先是由AmS接管主控制权力,然后AmS开始调度并运行Activity,WmS作为AmS的辅助服务,接受应用程序的请求创建窗口。当窗口显示后,用户和窗口的交互控制则交由WmS和应用程序本身来完成,而当应用程序需要启动新的Activity时,则又交给AmS去处理,系统就这样周而复始的运行。

以上过程是在两个进程、三个独立线程中异步完成的,从代码的角度解释以上执行过程:

  • 当要启动B时,AmS会调用WmS的addAppToken()添加一个token,该token对应的是新的Activity。然后再调用WmS的setAppStartingWindow()告诉WmS启动窗口的标题和图标,以便WmS能根据这两个信息创建一个启动窗口。WmS接收到这个命令后就开始去创建启动窗口了,创建的具体过程就是标准的添加窗口的过程。
  • 与此同时,AmS还去启动B对应的进程,如果进程已经存在,则运行一个ActivityThread实例。每个Activity都是从ActivityThread开始执行的,ActivityThread类是客户端程序的主类,Activity仅仅是一个回调而已。
  • 在接下来的一段时间里,AmS处于空闲状态。WmS内部则开始创建启动窗口,并可能已经创建完毕了启动窗口,但暂时不能显示该启动窗口。而ActivityThread内部也忙碌的启动进程并使ActivityThread就绪。
  • 当ActivityThread就绪后,就会通过IPC调用AmS的attachApplication(),通知AmS自己已经就绪,可以运行任何指定的Activity了。当AmS收到这个通知后,一方面会调用WmS的setAppVisibility()使其开始显示启动窗口,并调用WmS中的setFocusedApp()将新的AppWindowToken设为焦点窗口,然而此时由于真正的窗口还没有就绪,所以焦点窗口被调整为Null。另一方面则调用ActivityThread中内联类ApplicationThread的scheduleLaunchActivity(),请求其开始运行指定的Activity,这最终会调用执行到Activity类的onCreate()函数中。
  • 在接下来的一段时间里,在WmS中,由于真正的Activity窗口还没有被创建,因此当前的焦点窗口被调整为null,并且开始了启动动画。另一方面,在ActivityRecord类中则开始运行Activity的onCreate(),该函数最终会调用到setContentView(),这会间接的创建一个真正的Activity窗口。
  • 当ActivityThread内部执行到创建真正的Activity窗口时,会调用到WmS中的addWindow()函数,在该函数中,当添加完新窗口后,就会把焦点调整到新窗口中。

销毁Surface的过程

Surface的销毁有两种情况:

  • AmS调用WmS的setAppVisibility()设置指定应用窗口的可视状态。该方法会调用到relayoutWindow()方法,这里面会销毁窗口对应的Surface。
  • 当要删除窗口时,这个很容易理解,窗口都不在了,内部的Surface自然应该被销毁。


results matching ""

    No results matching ""