Android窗口管理

一、 概述

在Android系统中,从设计的角度来看,窗口管理系统是基于C/S模式的。整个窗口系统分为服务端和客户端两大部分,客户端负责请求创建窗口和使用窗口,服务端完成窗口的维护,窗口显示等。


在Client端,并不是直接和WindowManagerService交互,而是直接和本地对象WindowManager交互,然后由WindowManager完成和WindowManagerService的交互。对于Android应用来说这个交互是透明的,应用不能感知到WindowManagerService的存在



二、 窗口的定义

在android的应用框架中,窗口主要分为两种:

第一种是应用窗口:一个activity有一个主窗口,弹出的对话框也有一个窗口,Menu菜单也是一个窗口。在同一个activity中,主窗口、对话框、Menu窗口之间通过该activity关联起来。和应用相关的窗口表示类是PhoneWindow和Window,PhoneWindow继承于Window,针对手机屏幕做了一些优化工作。PhoneWindow只是一个窗口封装类,里面核心的是mDecorView这个变量,mDecorView是一个顶层的View,窗口的添加就是通过调用getDecorView()获取到mDecorView并且调用WindowManager.addView()把该View添加到WindowManager中。

第二种是公共界面的窗口:如最近运行对话框、关机对话框、状态栏下拉栏、锁屏界面等。这些窗口都是系统级别的窗口,不从属于任何应用,和activity没有任何关系。这种窗口没有任何窗口类来封装,直接调用WindowManager.addView()来把一个view添加到WindowManager中。

在应用初始化的时候,会首先生成一个Activity对象,此时该activity还没有属于他的一个窗口。紧接着通过调用attach()函数,在attach()函数里面该activity会调用PolicyManager.makeNewWindow()创建一个新的PhoneWindow,然后在activity的onCreate()生命周期里,一般应用都会调用setContentView()设置该activity的显示界面。在setContentView()里,框架会自动生成一个布局,该布局文件包含了如标题栏、ActionBar等元素,最重要的是包含了应用的contentView。这个布局对应的就是PhoneWindow里面的mDecorView。最后在activity将要显示出来之前,通过getWindow().getDecorView()获取到DecorView,并通过WindowManager.addView()把DecorView添加到WindowManager中。


Activity添加客户端窗口时序图



三、 窗口管理

Android的窗关管理是基于C/S模式的,并且使用独立进程的方式实现。窗口管理的服务端WindowManagerService运行在独立的进程system_server里,当应用程序需要创建窗口时,通过进程通信的方式请求WindowManagerService创建窗口,由WindowManagerService向应用程序传递和窗口相关的交互消息。所有程序的窗口都在服务端管理,窗口的显示和控制都在WindowManagerService里处理。

WindowManagerService主要完成了以下几部分功能:

1.窗口的添加和删除

2.窗口的显示和隐藏控制

3.Z-order顺序管理

4.焦点窗口和焦点应用的管理

5.输入法窗口管理和墙纸窗口管理

6.转场动画

7.系统消息收集和分发

服务端的实现代码是在/framework/base/services/java/com/android/server/wm/里,核心的几个类是:

WindowManagerService.java

WindowState.java

WindowToken.java

AppWindowToken.java

Session.java

InputManager.java

InputMonitor.java

类解释:

WindowManagerService负责完成窗口的管理工作;

WindowState和客户端窗口一一对应,应用调用WindowManager.addView()时,最终会在WindowManagerService添加一个WindowState与之一一对应。

WindowToken是一个句柄,保存了所有具有同一个token的WindowState。应用请求WindowManagerService添加窗口的时候,提供了一个token,该token标识了被添加窗口的归属,WindowManagerService为该token生成一个WindowToken对象,所有token相同的WindowState被关联到同一个WindowToken。如输入法添加窗口时,会传递一个mCurrToken,墙纸服务添加窗口时,会传递一个newConn.mToken。

AppWindowToken继承于WindowToken,专门用于标识一个Activity。AppWindowToken里的token实际上就是指向了一个Activity。ActivityManagerService通知应用启动的时候,在服务端生成一个token用于标识该Activity,并且把该token传递到应用客户端,客户端的Activity在申请添加窗口时,以该token作为标识传递到WindowManagerService。同一个Activity中的主窗口、对话框窗口、菜单窗口都关联到同一个AppWindowToken。

Session表示一个客户端和服务端的交互会话。一般来说不同的应用通过不同的会话来和WindowManagerService交互,但是处于同一个进程的不同应用通过同一个Session来交互。

InputManager和InputMonitor负责上层的消息分发功能。

WindowManagerService内部的几个重要成员变量:

ArrayList<WindowState> mWindows

HashMap<IBinder, WindowState> mWindowMap

ArrayList<WindowToken> mTokenList

ArrayList<AppWindowToken> mAppTokens

mWindows保存了系统中所有的WindowState;

mWindowMap保存了每个WindowState和客户端窗口的映射关系,客户端应用请求窗口操作时,通过mWindowMap查询到对应的WindowState;

mTokenList保存了所有的WindowToken

mAppTokens保存了所有的AppWindowToken



窗口管理服务端主要类图

一个Activity从启动到添加窗口的整个流程如下:

ActivityManagerService在接收到启动Activity请求时,首先生成一个token作为该Activity的唯一标识。然后调用WindowManagerService向其添加一个AppWindowToken,此AppWindowToken封装了Activity的token。接着AMS启动应用客户端进程并把token传递到该进程,在客户端进程里完成Activity的初始化。在Activity的attach()函数中,Activity完成PhoneWindow的创建,并且把token传递给PhoneWindow。在Activity调用WindowManager.addView()时,在WindowManager内部会把token和该View关联,真正向WindowManagerService申请创建窗口的时候,再把token传递给WindowManagerService。WindowManagerService接收到创建窗口的请求的时候,通过mTokenMap查询对应该token的AppWindowToken,如果为空则抛出异常,否则创建一个WindowState并完成初始化工作和其他数据结构的调整工作。在这个过程中,token贯穿了服务端的AMS、WMS和客户端的Activity、Window。


Activity启动过程中创建窗口的时序图



四、WMS中服务端和客户端的交互接口和数据结构

应用请求创建窗口时,和应用直接交互的是WindowManager对象。WindowManager只是一个接口,调用addView()创建窗口时正真交互的是WindowManagerImpl对象。WindowManagerImpl管理单个应用的所有本地窗口。应用调用addView()创建窗口时,WindowManagerImpl会生成一个ViewRoot对象与之相对应,并且把相应的参数LayoutParams保存起来。

addView()的执行流程如下:

(1)检查所添加的窗口是否已经添加过,不允许重复添加;

(2)如果所添加窗口为子窗口类型,找到其父窗口,并保存在内部变量中;

(3)创建一个新的ViewRoot,并保存对应的View(DecorView)和LayoutParams;

(4)调用ViewRoot的setView()方法,完成真正意义上的添加工作。

ViewRoot本质上是一个Handler,并且实现了ViewParent接口。ViewRoot的主要功能是:

1.负责分发消息事件,如Key、Motion事件等;

2.负责和WMS的交互,分发WMS的交互命令;

3.作为DecorView的parent,对DecorView进行draw、measure、layout等操作;

在addView()的第3、4步完成之后,ViewRoot就全权接管了和WMS的交互工作,DecorView不需要做任何交互动作。ViewRoot和WMS之间的双向对话,主要是通过以下两个数据结构进行的:

IWindowSession

IWindow

这两个数据结构都是标准的aidl接口,用于进程之间的同步通信。IWindowSession负责ViewRoot到WMS的单向请求,IWindow则用于WMS回调ViewRoot。在ViewRoot对象内部,存在着一个IWindowSession的静态成员和一个IWindow的非静态成员,所以一个进程里只有一个IWindowSession对象,但是可以有多个IWindow对象。

Window、WindowManager、DecorView、ViewRoot、IWindowSession、IWindowSession、WindowState、WindowManagerService之间的关系可用下图来表示:



在ViewRoot的构造函数中,调用getWindowSession()初始化静态成员sWindowSession和非静态成员mWindow。在第4步调用setView()方法时,ViewRoot会调用sWindowSession.add()方法,把IWindow添加到WMS中,WMS就会生成一个WindowState与之一一对应,并且把IWindow对象保存到WindowState内部作为回调的接口。之后所有WMS的命令,都会通过直接访问IWindow接口,以消息的形式分发到ViewRoot,ViewRoot来完成相应的处理,或对DecorView进行操作,或完成后通过sWindowSession报告给WMS。

一个窗口从添加到显示可用以下时序图表示:


窗口添加过程时序图


到此为止,整个窗口管理系统整体架构可表示如下:


窗口管理系统整体架构图

五、WindowState和Surface

从Client端调用WindowManager的addView()方法到WMS完成WindowState的初始化,在这整个过程中,只是完成了一个窗口数据结构的创建,也就是说,到现在为止,Client端的窗口和Server端的窗口已经建立了一种相对固定的连接关系,并且Client端和Server端之间能够正常通信,WMS能够透明的对Client端的窗口进行操作,同时WMS也能够接收Client端窗口的命令,对WindowState进行相应的调整。

一个WindowState想要显示在屏幕上,必须申请一个显示缓存,这个显示缓存的管理和维护是在底层图形模块实现的,在java层有一个操作的封装对象Surface。WindowState申请到Surface对象之后,会将此Surface对象的相关数据拷贝到Client端的ViewRoot中,ViewRoot中也维护了一个Surface对象,实际上这两个对象是指向同一块显示缓存。ViewRoot有了这块显示缓存的引用之后,即可以通过lockCanvas来获取绘画画布,绘制完毕之后通过unlockAndPostCanvas来将绘制内容刷新到显示缓存中。也就是说,Client端窗口和Server端窗口共用一个Surface,Client负责绘制Surface的内容,Server负责控制Surface在屏幕上的大小位置等。

ViewRoot通过IWindowSession的relayout()接口来向WMS发送请求命令,包括窗口的显示和隐藏,窗口的布局信息如位置大小,同时还会接收WMS的处理结果。WMS会根据屏幕大小和Client请求的布局参数来决定窗口最终的布局信息,同时也会根据Client请求的显示隐藏命令来返回一个有效的或者无效的Surface对象。通常一个窗口的显示过程为:

1.Client请求显示窗口,并且传递布局参数;

2.WMS根据布局参数,申请一个Surface对象并返回给Client;

3.Client对Surface进行绘画操作,完成后告诉WMS;

4.WMS将Surface显示在屏幕上,并且进行层级等相应调整;


窗口显示过程时序图

一个横跨Activity、View、ViewRoot、IWindowSession、IWindow、WindowState、WindowManagerService、Surface的整体概念如下如所示:


窗口管理系统完整架构图


更多相关文章

  1. Android(安卓)IPC 机制详解:IBinder
  2. Android(安卓)热更新是如何实现的?
  3. android studio中用svn来管理项目
  4. Android(安卓)内存泄漏调试
  5. Android消息传递机制Handler完全解析之1基础介绍
  6. 【Android】JSON数据的读写方法
  7. Android中使用OkHttp框架
  8. android中的内部类
  9. Android(安卓)AIDL

随机推荐

  1. ipset 使用
  2. envoy网络部署笔记
  3. 中国信安圈已被人盯上了!
  4. 代码分析平台CodeQL学习手记(一)
  5. CSS常用布局类型
  6. Oracle入选2020 Q4 Forrester Wave™ Gra
  7. vue与react的简单比较
  8. c++ vector模拟实现
  9. vue与react的简单比较(全局状态管理)
  10. 马哥架构班第五周作业