文中图片部分摘自网络。
WindowManagerService主要完成了以下几部分功能:
s 窗口的添加和删除
s 窗口的显示和隐藏控制
s Z-order顺序管理
s 焦点窗口和焦点应用的管理
s 输入法窗口管理和墙纸窗口管理
s 转场动画
s 系统消息收集和分发
一个App从启动到主窗口显示出来,需要App,ActivityManagerService(AMS),WindowManagerService(WMS),SurfaceFlinger(SF)等几个模块相互合作。App负责业务逻辑,绘制自己的视图;AMS管理组件、进程信息和Activity的堆栈及状态等等;WMS管理Activity对应的窗口及子窗口,还有系统窗口等;SF用于管理图形缓冲区,将App绘制的东西合成渲染在屏幕上。
IWindowSession.aidl
Aidl中关键字oneway表示用户请求相应功能时不需要等待响应可直接调用返回,非阻塞效果。
默认的跨进程操作是同步的,
所以transact()方法的执行会阻塞;指定FLAG_ONEWAY时,
表示Client的transact()是单向调用,执行后立即返回,无需等待服务端返回。
在android的应用框架中,窗口主要分为两种:
第一种是应用窗口:一个activity有一个主窗口,弹出的对话框也有一个窗口,Menu菜单也是一个窗口。在同一个activity中,主窗口、对话框、Menu窗口之间通过该activity关联起来。和应用相关的窗口表示类是PhoneWindow和Window,PhoneWindow继承于Window,针对手机屏幕做了一些优化工作。PhoneWindow只是一个窗口封装类,里面核心的是mDecorView这个变量,mDecorView是一个顶层的View,窗口的添加就是通过调用getDecorView()获取到mDecorView并且调用WindowManager.addView()把该View添加到WindowManager中。
DecorView是整个ViewTree的最顶层View,它是一个FrameLayout布局,代表了整个应用的界面。在该布局下面,有标题view和内容view这两个子元素,而内容view则是上面提到的mContentParent
第二种是公共界面的窗口:如最近运行对话框、关机对话框、状态栏下拉栏、锁屏界面等。这些窗口都是系统级别的窗口,不从属于任何应用,和activity没有任何关系。这种窗口没有任何窗口类来封装,直接调用WindowManager.addView()来把一个view添加到WindowManager中
https://blog.csdn.net/yhaolpz/article/details/68936932
在应用程序进程这一侧的每一个W对象,在WindowManagerService服务这一侧都有一个对应的WindowState对象,用来描述一个Activity窗口的状态。
WindowState是WMS中事实的窗口,而不是Window,WindowState是在WMS的addWindow方法中创建,包含了一个窗口的所有的属性,其中一个属性为mLayer,表示窗口在Z轴的位置,mLayer值越小,窗口越靠后,mLayer值越大,窗口越靠前,最前面的一个窗口就作为焦点窗口,可以接收触摸事件。
App主要是具体的UI业务需求。
AMS则是管理系统四大组件以及进程管理,尤其是Activity的各种栈以及状态切换等管理;
WMS则是管理Activiy所相应的窗口系统(系统窗口以及嵌套的子窗口);
SurfaceFlinger则是将应用UI绘制到frameBuffer(帧缓冲区),最终由硬件完成渲染到屏幕上;
· WMS继承于IWindowManager.Stub, 作为Binder服务端;
· WMS的成员变量mSessions保存着所有的Session对象,Session继承于IWindowSession.Stub, 作为Binder服务端;
· 成员变量mPolicy: 实例对象为PhoneWindowManager,用于实现各种窗口相关的策略;
· 成员变量mChoreographer: 用于控制窗口动画,屏幕旋转等操作;
· 成员变量mDisplayContents: 记录一组DisplayContent对象,这个跟多屏输出相关;
· 成员变量mTokenMap: 保存所有的WindowToken对象; 以IBinder为key,可以是IAppWindowToken或者其他Binder的Bp端;
o 另一端情况:ActivityRecord.Token extends IApplicationToken.Stub
· 成员变量mWindowMap: 保存所有的WindowState对象;以IBinder为key, 是IWindow的Bp端;
o 另一端情况: ViewRootImpl.W extends IWindow.Stub
· 一般地,每一个窗口都对应一个WindowState对象, 该对象的成员变量mClient用于跟应用端交互,成员变量mToken用于跟AMS交互.
Activity与Window有一些对象具有一定的对应关系:
AMS | WMS |
ActivityRecord | AppWindowToken |
TaskRecord | Task |
ActivityStack | TaskStack |
App跟AMS通信,会建立Session连接到WMS,后续便通过IWindowSesson跟WMS通信;
WMS跟SF通信,WMS建立SurfaceComposerClient,然后会在SF中创建Client与之对应, 后续便通过ISurfaceComposerClient跟SF通信。
WindowToken
/**
* Container of a set of related windows in the window manager. Often this is an AppWindowToken,
* which is the handle for an Activity that it uses to display windows. For nested windows, there is
* a WindowToken created for the parent window to manage its children.
*/
public class WindowToken extends WindowContainer<WindowState> {...}
AppWindowToken
/**
* Version of WindowToken that is specifically for a particular application (or
* really activity) that is displaying windows.
*/
public class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener {}
WindowState
/** A window in the window manager. */
public class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {.....}
WindowManagerService负责完成窗口的管理工作,WindowManagerService内部的几个重要成员变量:
s ArrayList<WindowState> mWindows
s HashMap<IBinder, WindowState> mWindowMap
s ArrayList<WindowToken> mTokenList
s ArrayList<AppWindowToken> mAppTokens
mWindows保存了系统中所有的WindowState。
mWindowMap保存了每个WindowState和客户端窗口的映射关系,客户端应用请求窗口操作时,通过mWindowMap查询到对应的WindowState。
mTokenList保存了所有的WindowToken。
mAppTokens保存了所有的AppWindowToken。
WindowState和客户端窗口一一对应,应用调用WindowManager.addView()时,最终会在WindowManagerService添加一个WindowState与之一一对应。
WindowToken是一个句柄,保存了所有具有同一个token的WindowState。应用请求WindowManagerService添加窗口的时候,提供了一个token,该token标识了被添加窗口的归属,WindowManagerService为该token生成一个WindowToken对象,所有token相同的WindowState被关联到同一个WindowToken。如输入法添加窗口时,会传递一个mCurrToken,墙纸服务添加窗口时,会传递一个newConn.mToken。
窗口主序的确定
WindowState是WMS中事实的窗口,而不是Window,WindowState是在WMS的addWindow方法中创建,包含了一个窗口的所有的属性,其中一个属性为mLayer,表示窗口在Z轴的位置,mLayer值越小,窗口越靠后,mLayer值越大,窗口越靠前,最前面的一个窗口就作为焦点窗口,可以接收触摸事件。因为窗口的切换,切换后的Z序(窗口的显示次序称为 Z 序)就可能不同,所以mLayer的值不是固定不变的。mLayer是通过WindowState的另一个成员变量mBaseLayer的值计算得到,mBaseLayer的值是固定不变的,只和窗口类型有关。mBaseLayer(称为主序)是WindowState的构造方法中赋值。
窗口子序的确定
系统中的窗口种类比较多,case个数都到31了。比如应用程序的窗口是2,电话类型的窗口是3,Toast窗口是8...,因为系统中同类型的窗口比较多,所以对返回的整数值乘以10000(WindowManagerService.TYPE_LAYER_MULTIPLIER),在加上1000(WindowManagerService.TYPE_LAYER_OFFSET),相当把Z轴划分成了31个值域,不同类型的窗口的Z轴位置都是处于两个不相交的值域之中,互相不打扰。OK,通过mBaseLayer,我们知道了窗口是如何排序的,一个窗口有可能需要依附在一个父窗口上,作为一个子窗口,所以除了主序的概念外,还有子序。
SubLayer(称为子序),SubLayer值是用来描述一个窗口是否属于另外一个窗口的子窗口,或者说SubLayer值是用来确定子窗口和父窗口之间的相对位置的。
一个Activity中有三个子窗口WindowState1、WindowState2、WindowState3,WindowState1WindowState2在窗口A的前面,WindowState3在A的后面,这几个兄弟窗口为什么可以这样排序呢,这就是mSubLayer的作用,子序越大,则相对其他兄弟窗口越靠前,反之,越靠后,如果为负数,就处在父窗口的后面,如窗口A中的WindowState3,子序是根据窗口类型调用subWindowTypeToLayerLw确定的,subWindowTypeToLayerLw同样是在Window的构造方法中调用的。
链接 :https://blog.csdn.net/luoshengyang/article/details/8498908
Activity管理服务ActivityManagerService中每一个ActivityRecord对象在Window管理服务WindowManagerService中都对应有一个AppWindowToken对象。
此外,在输入法管理服务InputMethodManagerService中,每一个输入法窗口都对应有一个Binder对象,这个Binder对象在Window管理服务WindowManagerService又对应有一个WindowToken对象。
与输入法窗口类似,在壁纸管理服务WallpaperManagerService中,每一个壁纸窗口都对应有一个Binder对象,这个Binder对象在Window管理服务WindowManagerService也对应有一个WindowToken对象。
在Window管理服务WindowManagerService中,无论是AppWindowToken对象,还是WindowToken对象,它们都是用来描述一组有着相同令牌的窗口的,每一个窗口都是通过一个WindowState对象来描述的。例如,一个Activity组件窗口可能有一个启动窗口(Starting Window),还有若干个子窗口,那么这些窗口就会组成一组,并且都是以Activity组件在Window管理服务WindowManagerService中所对应的AppWindowToken对象为令牌的。从抽象的角度来看,就是在Window管理服务WindowManagerService中,每一个令牌(AppWindowToken或者WindowToken)都是用来描述一组窗口(WindowState)的,并且每一个窗口的子窗口也是与它同属于一个组,即都有着相同的令牌。
其中,Activity Stack是在ActivityManagerService服务中创建的,Token List和Window Stack是在WindowManagerService中创建的,而Binder for IM和Binder for WP分别是在InputMethodManagerService服务和WallpaperManagerService服务中创建的,用来描述一个输入法窗口和一个壁纸窗口。
AppWindowToken继承于WindowToken,专门用于标识一个Activity。AppWindowToken里的token实际上就是指向了一个Activity。ActivityManagerService通知应用启动的时候,在服务端生成一个token用于标识该Activity,并且把该token传递到应用客户端,客户端的Activity在申请添加窗口时,以该token作为标识传递到WindowManagerService。同一个Activity中的主窗口、对话框窗口、菜单窗口都关联到同一个AppWindowToken。
一个WindowState想要显示在屏幕上,必须申请一个显示缓存,这个显示缓存的管理和维护是在底层图形模块实现的,在java层有一个操作的封装对象Surface。WindowState申请到Surface对象之后,会将此Surface对象的相关数据拷贝到Client端的ViewRoot中,ViewRoot中也维护了一个Surface对象,实际上这两个对象是指向同一块显示缓存。ViewRoot有了这块显示缓存的引用之后,即可以通过lockCanvas来获取绘画画布,绘制完毕之后通过unlockAndPostCanvas来将绘制内容刷新到显示缓存中。也就是说,Client端窗口和Server端窗口共用一个Surface,Client负责绘制Surface的内容,Server负责控制Surface在屏幕上的大小位置等。
WindowManagerService类有三个成员变量mTokenMap、mTokenList和mAppTokens,它们都是用来描述系统中的窗口的。
成员变量mTokenMap指向的是一个HashMap,它里面保存的是一系列的WindowToken对象,每一个WindowToken对象都是用来描述一个窗口的,并且是以描述这些窗口的一个Binder对象的IBinder接口为键值的。例如,对于Activity组件类型的窗口来说,它们分别是以用来描述它们的一个ActivityRecord对象的IBinder接口保存在成员变量mTokenMap所指向的一个HashMap中的。
成员变量mTokenList指向的是一个ArrayList,它里面保存的也是一系列WindowToken对象,这些WindowToken对象与保存在成员变量mTokenMap所指向的一个HashMap中的WindowToken对象是一样的。成员变量mTokenMap和成员变量mTokenList的区别就在于,前者在给定一个IBinder接口的情况下,可以迅速指出是否存在一个对应的WindowToken对象,而后者可以迅速遍历WindowManagerService服务中的WindowToken对象。
成员变量mAppTokens指向的也是一个ArrayList,不过它里面保存的是一系列AppWindowToken对象,每一个AppWindowToken对象都是用来描述一个Activity组件窗口的,而这些AppWindowToken对象是以它们描述的窗口的Z轴坐标由小到大保存在这个ArrayList中的,这样我们就可以通过这个ArrayList来从上到下或者从下到上地遍历系统中的所有Activity组件窗口。由于这些AppWindowToken对象所描述的Activity组件窗口也是一个窗口,并且AppWindowToken类是从WindowToken继承下来的,因此,这些AppWindowToken对象还会同时被保存在成员变量mTokenMap所指向的一个HashMap和成员变量mTokenList所指向的一个ArrayList中。
在WMS中,一个窗口对应一个WindowState,它跟上述动画类之间的组织形式如下:
对应关系如下:
AppWindowToken跟Activity是一对一关系,而一个Activity可以有多个窗口,所以AppWindowAnimator对应多个WindowState
一个WindowState对应一个WindowStateAnimator
ScreenRotationAnimation跟屏幕一一对应,如果有,它会施加到所有可见窗口上