理解WindowManager与WindowManageService:

目录

 

理解WindowManager:

 

 

 

1.window,WindowManager和WMS:

 

 

 

 

2. WindowManager的关联类:

3.Window的属性:

 

 

3.1:Window的类型和显示次序:

 

 

 

 

3.2Window的标志:

 

 

 

3.3:软键盘的相关模式:

4.Window的操作:

4.1:系统窗口的添加过程:

 

 

 

4.2:Activity的添加过程:

 

 

 

4.3:Window的更新过程:

 

 

 

 

理解WindowManageService:

 

 

1.WMS的职责:

 

 

 

2.WMS的创建过程:

 

 

 

2.1:简述system_server,android.display和android.ui关系:

3.WMS的重要成员:

4.WMS的添加过程(WMS部分):

 

 

 

4.1:addWindow方法总结:

 

 

 

5.Window的删除过程:

5.1:删除总结:


 

理解WindowManager:

 

为了更好的理解WindowManageService,需要先了解一下WindowManager的相关知识,从应用开发的角度来看,WindowManager也是与WMS最紧密的类。

 

 

 

1.window,WindowManager和WMS:

Window它是一个抽象类,具体的实现类为PhoneWindow,它对View进行管理。WindowManager是一个接口类,继承自接口ViewManager,是来管理Window的,它的实现类为WindowManagerImpl。如果想要对Window进行添加,更新和删除操作就可以使用WindowManager,WindowManager会将具体的工作交给WMS来处理。两者通过Binder进行通信,WMS作为系统服务有很多的API是不会暴露给WindowManager的,这一点与ActivityManager和AMS的关系有点类似。

 

 

4a7c80bae40548b2854527da8a09cae1.png

 

 

 

 

2. WindowManager的关联类:

WindowManager是一个接口类,继承自接口ViewManager,ViewManager中定义了3个方法,分别用于添加,更新和删除View。WindowManager也继承了这些方法,而这些方法传入的参数都是View类型的。WindowManager在继承ViewManager的同时,又加入了很多的功能,包括Window的类型和层级相关的常量,内部类以及一些方法,其中有两个方法是根据Window的特性加入的:1.getDefaultDisplay方法;2.removeViewImmediate方法。前者得到WindowManager所管理的屏幕,后者规定在这个方法返回前要立即执行View.onDetachedFromWindow,来完成View相关的销毁工作。

 

frameworks/base/core/java/android/view/ViewManager.java

 

 

我们来看PhoneWindow是什么时候被创建的呢?在Activity启动过程中会调用ActivityThread的performLaunchActivity方法,而performLaunchActivity方法又会调用Activity的attach方法,PhoneWindow就是在Activity的attach方法中创建的。

我们来看Activity的attach方法与PhoneWindow相关的代码:在创建一个PhoneWindow对象之后,调用它的setWindowManager方法//①。该方法会判断如果传入的WindowManager为null,就会调用Context的getSystemService方法,并且传入服务名称:Context.WINDOW_SERVICE,getSystemService方法在ContextImpl中实现。它会调用SystemServiceRegistry的getSystemServiceName方法,返回了SYSTEM_SERVICE_NAMES(是一个HashMap类型的数据,用来存储服务的名称)。

那么Context.WINDOW_SERVICE对应什么?在SystemServiceRegistry的静态代码块中会调用多个registerService方法,这里只列举与Context.WINDOW_SERVICE相关的。registerService方法内部会将传入的服务的名称存入到SYSTEM_SERVICE_NAMES中。还有createService方法也可以看出Context.WINDOW_SERVICE对应的就是WindowManagerImpl实例。所以到这里看出Context的getSystemService方法得到的就是WindowManagerImpl实例。

//①:我们再回到setWindowManager方法的createLocalWindowManager方法,它也是创建了WindowManagerImpl实例。不同的是这次创建WindowManagerImpl时将创建它的Window作为参数传进来了,这样WindowManagerImpl就持有了Window的引用,可以对Window进行操作。

 

 

WindowManagerImpl虽然是WindowManager的实现类,但是没有实现什么功能,而是将功能委托给了WindowManagerGlobal,使用的是桥接模式。WindowManagerGlobal使用的是单例模式。

 

 

bb74cea5b328480ea923779e12a014b1.png

 

总结:PhoneWindow继承自Window,Window通过setWindowManager方法与WindowManager相关联。WindowManager继承自接口ViewManager,WindowManagerImpl是WindowManager接口的实现类,但是具体的功能都会委托给WindowManagerGlobal来实现。

 

 

 

 

3.Window的属性:

Window的属性有很多种,与应用开发最密切的有3种,分别为Type(Window的类型),Flag(Window的标志)和SoftInputMode(软键盘相关模式)。

 

frameworks/base/core/java/android/view/WindowManager.java

 

 

 

3.1:Window的类型和显示次序:

Window的类型有很多种,总的来说可以分为三大类型,分别是:Application Window(应用程序窗口),Sub Window(子窗口),System Window(系统窗口)。每个大的类型中又包含了很多种类型,它们都定义在WindowManager的静态内部类LayoutParams中。

  1. 应用程序窗口:Activity就是一个典型的应用程序窗口。Type值范围为1-99,这个大小涉及窗口的层级。

  2. 子窗口:顾名思义,它不能独立存在,需要依附在其他窗口才可以,PopupWindow就是属于子窗口。Typpe值范围为1000-1999。

  3. 系统窗口:Toast,输入法窗口,系统音量窗口,系统错误窗口都是属于系统窗口。系统窗口的类型接近40个,Type值为2000-2999.

  4. 窗口显示次序:当一个进程向WMS申请一个窗口时,WMS会为窗口确定显示的次序,为了方便窗口的显示次序的管理,手机屏幕可以虚拟的用X,Y,Z轴来表示,其中Z轴垂直于屏幕上,从屏幕内到外,以此确定窗口显示次序也就是确定窗口在Z轴上的次序,这个次序也叫做Z-Oder。Type值是Z-Oder排序的依据。在一般情况下,Type值越大则Z-Oder排序越靠前,就越靠近用户。当然还有其他情况。

 

 

 

 

3.2Window的标志:

Window的标志也就是Flag,用于控制Window的显示,同样被定义在WindowManager的静态内部类LayoutParams中。一共有20多个,具体自查。而设置Window的Flag有3种方法,第一种是通过Window的addFlags方法;第二种是通过Window的setFlags方法;其实使用addFlags方法时内部会调用setFlags方法。第三种是给LayoutParams设置Flag,并且通过WindowManager的addView方法进行添加。

 

 

 

3.3:软键盘的相关模式:

例如在典型的用户登录界面中,弹出来的软键盘窗口盖住了输入框,那么用户体验就不好。为了使软键盘窗口能够按照期望的显示,WindowManager的静态内部类LayoutParams中定义了软键盘的相关模式。我们除了可以在AndroidManifest中Activity的属性android:windowSoftInputMode设置以外,还可以使用window设置SoftInputMode。

 

 

 

 

4.Window的操作:

WindowManager对Window进行管理,说到管理那就离不开对Window的添加,删除和更新操作,这些操作统称为Window的操作。对于Window的操作,最终是交给WMS来处理的。窗口的操作可以分为两大部分,一部分是WindowManager的处理部分,另一部分是WMS的处理部分。而Window的类型总的来说可以分为三部分:Application Window(应用程序窗口),Sub Window(子窗口),System Window(系统窗口)。对于不同的类型窗口添加过程会有所不同,但是对于WMS处理部分,添加过程基本上都是一样的。下面会主要写WindowManager的处理部分,WMS的处理部分下一节写。

 

 

 

4.1:系统窗口的添加过程:

因为Window分为三部分,不同类型的Window添加过程也不尽相同,这里主要写系统窗口StatusBar,它是SystemUI的重要组成部分,具体是指系统状态栏,用于显示时间,电量和信号等等信息。其中不同的系统窗口的添加过程也有所区别。而StatusBar的addStatusBarWindow方法负责给StatusBar添加Window。

 

frameworks/base/package/SystemUI/com/android/systemui/statusbar/phone/StatusBar.java

在addStatusBarWindow方法中调用makeStatusBarView方法构建StatusBar的视图,并在后续调用StatusBarWindowManager的add方法,将StatusBar的视图和StatusBar的高度传进去。在add方法中创建了LayoutParams来配置StatusBar视图的属性。然后调用了WindowManager的addView方法,实现在WindowManagerImpl中。该类会调用WindowManagerGlobal的addView方法。

frameworks/base/core/java/android/WindowManagerImpl.java

 

WindowManagerGlobal中维护和Window操作相关的三个列表,在窗口的添加,更新和删除的过程中都会涉及这3个列表,它们分别是View列表(Array<View> mViews),布局参数列表(ArrayList<WindowManager.LayourParams> mParams)和ViewRootImpl列表(ArrayList<ViewRootImpl> mRoots)。//④

 

继续来看addView方法:首先对参数进行检查,然后如果当前窗口要作为子窗口的话,就会使用parentWindow.adjustLayoutParamsForSubWindow方法调整它的wparams对象。接着把参数添加到上述三个列表中。然后调用ViewRootImpl的setView方法并且传入参数。

setView方法相关的逻辑为调用了IWindowSession类型的mWindowSession对象的addToDisplay方法,它是一个Binder对象,用于进行进程之间的通信。IWindowSession类型是Client端的代理,它的server端的实现为Session。Session的addToDisplay方法则运行在WMS所在的进程。本地进程的ViewRootImpl想要和WMS通信的话就要经过Session。

Session的addToDisplay方法调用了WMS的addWindow方法//③,并且将自己的Session传进去,每个应用程序进程都会对应一个Session,WMS会用ArrayList保存,剩下的工作就交给WMS处理了。包括为这个添加窗口分配Surface,启动窗口的次序等等。

frameworks/base/core/java/android/view/ViewRootImpl.java

frameworks/base/services/core/java/com/android/server/wm/Session.java

 

 

 

4.2:Activity的添加过程:

无论哪种窗口在WMS处理部分都是类似的,但是在WindowManager处理部分会有所不同。当界面要和用户交互时,就会调用ActivityThread的handleResumeActivity方法。在该方法中的performResumeActivity方法最终会调用Activity的onResume方法。然后通过getWindowManager方法获取了ViewManager类型的对象,并且后续调用它的addView方法,后面的过程与上面一样。

 

 

 

4.3:Window的更新过程:

Window的更新过程和Window添加过程是类似的。需要调用ViewManager的updateViewLayout方法,该方法在WindowManagerImpl中实现,它会调用WindowManagerGlobal的updateViewLayout方法。

 

updateViewLayout方法:调用setLayoutParams设置更新的参数到View,接着调用ViewRootImpl类型的get方法根据索引得到窗口的ViewRootImpl,然后调用remove方法和add方法更新布局参数列表,最后调用ViewRootImpl的setLayoutParams方法将更新的参数设置到ViewRootImpl中。而setLayoutParams方法最后会调用ViewRootImpl的scheduleTraversals方法。

scheduleTraversals方法关注Choreographer的postCallback方法用于发起添加回调,这个添加回调将在下一帧渲染时控制执行。其中Choreographer用于接收系统的VSync信号,在下一帧渲染时控制执行一些操作。这个添加的回调指的是参数TraversalRunnable。TraversalRunnable的run方法中调用了doTraversal方法,在该方法中又调用了performTraversals方法更新了Window视图和执行了WIndow的View工作流程。

 

 

 

 

理解WindowManageService:

WMS它不仅仅是是WindowManage的管理者,它还有许多重要的职责。

 

 

1.WMS的职责:

  1. 窗口管理:WMS是窗口的管理者,它负责窗口的启动,添加和删除,另外窗口的大小和层级也是由WMS进行管理的。窗口管理的核心成员有DisplayContent,WindowToken和WindowState。
  2. 窗口动画:窗口之间进行切换时,使用窗口动画可以显得效果好一点,窗口动画由WMS的动画子系统来负责,动画子系统的管理者为WindowAnimator。
  3. 输入系统的中转站:通过对窗口的触摸从而产生触摸事件,IMS会对触摸事件进行处理,它会寻找一个最合适的窗口来处理触摸反馈信息,WMS是窗口的管理者,作为中转站最合适不过了。
  4. Surface管理:窗口并不具备绘制功能,因此每个窗口都需要一块Surface来供自己绘制,为每个窗口分配Surface是由WMS来完成的。

 

 

079cd72c7716485795739c1422cfebd1.png

 

 

 

2.WMS的创建过程:

WMS涉及的知识点非常多,我们先来看看WMS是如何被创建的,回到SystemServer进程创建的WMS开始。我们知道在SystemServer的main方法中调用startOtherServices方法启动了其他服务,其他服务大概有100个左右,其中包括WMS的启动。

 

我们来看startOtherServices方法启动WMS相关部分,剩余的其他服务的启动逻辑也大同小异。首先调用Watchdog.getInstance方法获取Watchdog实例,后续通过Watchdog.init方法对它初始化。后续还会提到//①。然后创建了IMS,并且赋值给IMS类型的inputManager对象。然后执行WMS的main方法,传入IMS参数等。其实WMS的main方法是运行在SystemServer的run方法中的,换句话说就是运行在system_server线程中。后续也会提到//②。接着调用ServiceManager的addService方法把WMS和IMS注册到SystemManager中。这样的话,如果某个客户端想要使用WMS的话,就先去SystemManager中查询信息,再根据信息与WMS所在的进程建立通信,客户端就可以使用WMS了。然后调用displayReady方法初始化屏幕显示信息。接着调用systemReady方法通知WMS,系统的初始化工作已经完成。

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

 

 

我们来看WMS的main方法:相关的DisplayThread.getHandler().runWithScissors()方法,其中DisplayThread.getHandler()方法用来得到DisplayThread的Handler实例,而DisplayThread是一个单例的前台线程,这个线程用来处理需要低延时的相关操作,并且只能由WindowManager,DisplayManager和InputManager实时执行快速操作。

 

接着.runWithScissors()方法,它对参数进行判断后,再判断当前线程system_server线程是否指向Handler所指向的线程android.display线程,是的话执行Runnable的run方法,不是的话则调用BlockingRunnable的postAndWait方法,并且将参数Runnable传进去。补充:runWithScissors()方法的参数1是一个Runnable,它的run方法包括创建WMS的实例的代码。

 

 

WMS的构造方法:相关的保存了IMS,这样WMS就有了IMS的引用,然后通过DisplayManager的getDisplays方法得到Display数组(每个显示设备都有一个Display实例),接着遍历Display数组,接着调用createDisplayContentLocked方法将Display封装为DisplayContent,它用来描述一块屏幕。然后获取AMS实例,持有AMS的引用。然后通过initPolicy方法初始化窗口管理策略的接口类WindowManagerPolicy,它用来定义一个窗口策略所要遵循的通用规范。//①:接着WMS把自己通过addMonitor方法添加到Watchdog中去。Watchdog是用来监控系统的一些关键服务的运行状况,这些被监控的服务都会实现Watchdog.Monitor接口。Watchdog每分钟都会对被监控的系统服务进行检查,如果这些系统服务出现了死锁,则会杀死Watchdog所在的进程,也就是SystemServer进程。

 

 

我们来看initPolicy方法:它调用了UIThread.getHandler().runWithScissors方法,在runWithScissors方法中1参是一个Runable,它的run方法,执行了WindowManagerPolicyThread的set方法和WMP的init方法,WMP是一个接口,init方法具体在PWM中实现。PWM的init方法运行在android.ui线程中,它的优先级高于initPolicy方法所在的android.display线程。

2.1:简述system_server,android.display和android.ui关系:

b5fc2dae950042568d410d35103651d7.png

 

 

  1. 首先在system_server线程中执行了SystemServer的startOtherServices方法,startOtherServices方法中会调用WMS的main方法,main方法会创建WMS,创建的过程在android.display线程中实现,创建WMS的优先级更高,所以system_server线程要等待WMS创建完成之后,处于等待状态的system_server线程才会被唤醒继续执行。
  2. 在WMS的构造方法中会调用WMS的initPolicy方法,在该方法中调用了PWM的init方法,PWM的init方法在android.ui线程中运行,它的优先级要高于android.display线程,因此android.display线程要等PWM的init方法执行完成之后,处于等待状态的android.display程才会被唤醒继续执行。
  3. PWM的init方法执行完成之后,android.display线程就完成了WMS的创建,等待的system_server线程会被唤醒继续执行WMS的main方法之后的代码。例如displayReady方法。

 

 

 

3.WMS的重要成员:

要想更好的了解WMS,不仅仅要了解WMS的创建,还要知道WMS的重要成员变量。例如:

  1. mPolicy:mPolicy是WindowManagerPolicy(WMP)类型的变量。WMP是窗口管理策略的接口类,用来定义一个一个窗口策略所要遵循的通用规范,并且提供了WindowManger所有的特定的Ui行为。它的具体实现类为PhoneWindowManager,这个实现类在WMS创建的时候被创建。WMP允许定制窗口层级和特殊窗口类型以及关键的调度和布局。
  2. mSessions:mSessions是ArraySet类型的变量,元素类型为Session,它主要用于进程之间的通信。其他的应用程序进程想要与WMS进程进行通信就需要经过Session,并且每个应用程序进程都会对应一个Session,WMS保存这些Session用来记录所有向WMS提出窗口管理服务的客户端。
  3. mWindowMap:mWindowMap是WindowHashMap类型的变量,WindowHashMap继承了HashMap,它限制了HashMap的key值类型为IBinder,value值类型为WindowState。WindowState用于保存窗口的信息,在WMS中它用来描述一个窗口,所以mWindowMap就是保存WMS中各种窗口的集合。
  4. mFinishedStarting:mFinishedStarting是ArrayList类型的变量,元素类型为AppWindowToken,它是WindowToken的子类。WindowToken可以理解为窗口的令牌,当应用程序想要向WMS申请一个窗口,则需要向WMS出示有效的WindowToken,AppWindowToken作为WindowToken的子类,主要描述应用程序的WindowToken结构,应用程序中每个Activity都对应一个AppWindowToken。WindowToken会将同一个组件的窗口WindowState集合在一起,方便管理。而mFinishedStarting就是存储已经完成启动的应用程序窗口的AppWindowToken的列表。除了mFinishedStarting以外,还有mFinishedEarlyAnim,mWindowReplacementTimeouts。
  5. mResizingWindows:mResizingWindows是ArrayList类型的变量,元素类型为WindowState,mResizingWindows是用来存储正在调整大小的窗口的列表,与mResizingWindows类似的还有mPendingRemove,mDestroySurface和mDestroySurface等等。窗口保存这些Surface是因为,窗口在经历Surface变化时,窗口要保存旧的Surface,直到Surface的第一帧绘制完成。
  6. mAnimator:mAnimator是WindowAnimator类型的变量,用于管理窗口的动画以及特效动画。
  7. mH:mH是H类型的变量,系统的Handler类,用于将任务加入到主线程的消息队列中。
  8. mInputManager:mInputManager是InputManagerService(IMS)类型的变量,输入系统的管理者。IMS会对触摸事件进行处理,它会寻找一个最合适的窗口来处理触摸反馈信息。WMS是窗口的管理者,故作为中转站。

 

 

 

4.WMS的添加过程(WMS部分):

现在到了window操作的WMS的处理部分,无论是系统窗口的添加过程还是Activity,它们的Window的添加过程都会调用WMS的addWindow方法//③。WMS的addWindow方法返回的是addWindow的各种状态,这些状态被定义在WindowManagerGlobal中。WMS的addWindow方法我们要关注的有:

根据Window的属性调用WMP的checkAddPermission方法来检查权限,具体在PhoneWindowManager的checkAddPermission方法中实现,如果没有权限就不会执行下面的逻辑。接着看getDisplayContentOrCreate方法传入displayId参数来获取窗口要添加到哪个DisplayContent上,如果没有找到DisplayContent,则返回WindowManagerGlobal.ADD_INVALID_DISPLAY。其中DisplayContent用来描述一块屏幕。然后看if语句的type判断,判断是什么窗口。接着看如果是子窗口的话,就会调用windowForClientLocked方法根据attrs.token作为key得到父窗口。其中attrs.token是IBinder类型的对象。

调用displayContent的getWindowToken方法获取WindowToken,接着看如果WindowToken为null,则根据rootType或者type值进行区分判断,之后隐式的创建WindowToken。如果WindowToken不为空的话,也是根据rootType或者type值判断窗口,根据不同的窗口类型转换WindowToken。然后创建WindowState,它保存窗口的所有的状态信息,在WMS中它代表一个窗口。接着看如果win.mDeathRecipient()==null,或者win.getDisplayContent()==null的话就不会执行下面的逻辑。两者代表的是窗口的客户端是否已经死亡和窗口的DisplayContent是否为null。继续看WMP的adjustWindowParamsLw方法,该方法在PhoneWindowManager中实现,它会根据窗口的type值对窗口的LayoutParams的一些成员变量进行修改。接着看调用WMP的prepareAddWindowLw方法,用于准备将窗口添加到系统中。然后看将WindowState添加到mWindowMap中。接着看调用win.mToken.addWindow方法将WindowState添加到该WindowState对应的WindowToken,实际上是保存WindowToken的父类中,这样WindowToken就包含了同一个组件的WindowState。

 

 

 

4.1:addWindow方法总结:

addWindow方法主要做了:

  1. 对所要添加的窗口进行检查,如果窗口不满足一些条件,就不再执行下面的逻辑。
  2. WindowToken相关的处理。
  3. WindowState的创建和相关的处理,并且将WindowState和WindowToken相关联。
  4. 创建和配置DisplayContent,完成窗口添加到系统之前的准备工作。

 

 

 

5.Window的删除过程:

要删除Window需要先调用WindowManagerImpl的removeView方法,在removeView方法中又会调用WindowManagerGlobal的removeView方法。它内部会调用findViewLocked找到在view列表的索引,再调用removeViewLocked方法并且传入找到的。

frameworks/base/core/java/android/view/WindowManagerGlobal.java

removeViewLocked方法调用mRoots.get方法获取传入索引在ViewRootImpl列表中的ViewRootImpl,再调用InputMethodManager.getInstance方法获取InputMethodManage实例,然后调用root.die方法,该方法会根据传入参数,如果为true,并且mIsInTraversal为false,则执行doDie方法,并且此时ViewRootImpl不再执行performTraversals方法。

doDie方法调用checkThread方法检查执行doDie方法线程的正确性。如果它有子view的话就会调用dispatchDetachedFromWindow方法来销毁view,否则调用WindowManagerGlobal的doRemoveView方法,从三个列表中清除相关的元素//④。

dispatchDetachedFromWindow方法中主要调用了IWindowSession的remove方法,IWindowSession在Server端实现为Session。Session的remove方法调用了WMS的removeWindow方法,该方法会通过windowForClientLocked方法获取对应的WindowState,WindowState是保存窗口的信息的。接着调用WindowState的removeIfPossible方法,removeIfPossible方法调用了另一个removeIfPossible方法,这个方法不是直接执行删除的,而是进行多个条件的过滤,满足一个条件就会return,推迟删除操作。通过条件判断之后,就会执行removeImmediately方法用于立即进行删除操作。

 

 

 

5.1:删除总结:

  1. 检查线程的正确性。
  2. 从三个列表中删除与它对应的元素。
  3. 判断是否可以直接执行删除操作。
  4. 执行删除操作,释放资源。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mo@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值