转载地址:http://www.cnblogs.com/samchen2009/p/3364327.html
Android的GUI系统是Android最重要也最复杂的系统之一。它包括以下部分:
它们之间的关系如下图所示
只有对这些系统的功能和工作原理有基本的了解,我们才能够解答一些经常萦绕在脑海里的问题,比如说:
本文将从框架和流程角度出发,试图对Android的GUI系统做一个简要但全面的介绍,希望借此能够帮助大家找到上述问题的答案。
所有的内容可以浓缩在下面这张图里,里面有很多的名称和概念我们需要事先解释一下:
View 是一个矩形的可见区域。
ViewGroup 是一种特殊的View, 它可以包含其他View并以一定的方式进行布局。Android支持的布局有FrameLayout, LinearLayout, RelativeLayout 等。
DecorView 是FrameLayout的子类,FrameLayout 也叫单帧布局,是最简单的一种布局,所有的子View在垂直方向上按照先后顺序依次叠加,如果有重叠部分,后面的View将会把前面的View挡住。我们 经常看到的弹出框,把后面的窗口挡住一部分,就是用的FrameLayout布局。Android的窗口基本上用的都是FrameLayout布局, 所以DecorView也就是一个Activity Window的顶级View, 所有在窗口里显示的View都是它的子View.
ViewRoot . 我们可以定义所有被addView()调用的View是ViewRoot, 因为接口将会生成一个ViewRootImpl 对象,并保存在WindowManagerGlobal的mRoots[] 数组里。一个程序可能有很多了ViewRoot(只要多次调用addView()), 在WindowManagerService端看来,就是多个Window。但在Activity的默认实现里,只有mDecorView 通过addView 添加到WindowManagerService里( 见如下代码)
//frameworks/base/core/java/android/app/Activity.java void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); }
因此一般情况下,我们可以说,一个应用可以有多个Activity,每个 Activity 一个Window(PhoneWindow), 每个Window 有一个DecorView, 一个ViewRootImpl, 对应在WindowManagerService 里有一个Window(WindowState).
WindowManagerImpl: 实现了WindowManager 和 ViewManager的接口,但大部分是调用WindowManagerGlobals的接口实现的。
WindowManagerGlobals: 一个SingleTon对象,对象里维护了三个数组:
同时,它还维护了两个全局IBinder对象,用于访问WindowManagerService 提供的两套接口:
ViewRootImpl:
ViewRootImpl 在整个Android的GUI系统中占据非常重要的位置,如果把Activity和View 看作 'MVC' 中的V, 把各种后台服务看作Modal,ViewRootImpl 则是'MVC' 中的'C' - Controller. Controller在MVC架构里承担着承上启下的作用,一般来说它的逻辑最为复杂。从下图可以看到,ViewRootImpl 与 用户输入系统(接收用户按键,触摸屏输入), 窗口系统(复杂窗口的布局,刷新,动画),显示合成系统(包括定时器Choreograph, SurfaceFlinger), 乃至Audio系统(音效输出)等均有密切的关联。研究ViewRootImpl 是研究Android整个窗口系统的核心和切入点,我们将在后面详细讨论ViewRootImpl的实现和作用。
三 者( ViewRootImpl, WindowManagerImpl, WindowManagerGlobal) 都存在于应用(有Activity)的进程空间里,一个Activity对应一个WindowManagerImpl, 一个DecorView(ViewRoot),以及一个ViewRootImpl (上面说过,实际一个Activity只有一个DecorView),而WindowManagerGlobals是一个全局对象,一个应用永远只有一 个。
注意的是,在某些情况下,一个应用可能会有几个ViewRootImpl对象,比如说ANR是弹出的对话框,或是网页里面一个视频窗口 (SurfaceView), 在WindowManagerService看来,它们也是一个窗口。同时,SystemServer的进程空间也有自己的 WindowManagerGlobals 和若干个ViewRoot, 因为WindowManagerService 内部也会管理某些系统窗口,如手机顶部的StatusBar, 手机底部的NavigationBar, 以及 锁屏(KeyGuard)窗口,这些窗口不属于某个特定的Activity。
WindowManager: 是一个接口类,定义了一些接口来管理Acitivity里的窗口。WindowManager 是Android应用进程空间里的一个对象,不提供IPC服务。
WindowManagerService: 是SystemServer进程里的一个Service,它的主要功能有
WindowManagerService 是Android Framework里最为庞大复杂的模块之一,我们后面会从各个方面对它进行尽可能详细的分析。
Token在英语中表示标记,信物的意思,在代码中,有点类似Handle,Cookie, ID, 用来标识某个特定的对象。在Android的窗口系统中,有很多的’Token', 它们代表着不同的含义。
WindowToken: 是在WindowManagerService 中定义的一个基类,顾名思义,它是用来标识某一个窗口。和下面的appWindowToken相比, 它不属于某个特定的Activity, 比如说输入法窗口,状态栏窗口等等。
appWindowToken: 顾名思义,它是用来标识app, 跟准确的说法,是用来标识某个具体的Activity.
ApplicationToken: 指的是ActivityRecord 类里的Token子类。appWindowToken里的appToken也就是它。
appToken: 和applicationToken是一个意思。
下 图描绘了各个Token之间的关系。一个Token下面带一个WindowList队列,里面存放着隶属与这个Token的所有窗口。当一个Window 加入WindowManagerService 管理时,必须指定他的Token值,WindowManagerService维护着一个Token与WindowState的键值Hash表。
通过 ‘dumpsys window tokens' 我们可以列出WindowManagerService当前所有的Token 和 窗口。比如,
WINDOW MANAGER TOKENS (dumpsys window tokens) All tokens: WindowToken{4ea639c4 null}: //token = NULL windows=[Window{4ea7670c u0 Application Not Responding: jackpal.androidterm}, Window{4ea63a08 u0 Keyguard}] windowType=-1 hidden=false hasVisible=true AppWindowToken{4eb29760 token=Token{4eb289d4 ActivityRecord{4ea87a20 u0 com.android.launcher/com.android.launcher2.Launcher}}}: //Launcher2 windows=[Window{4ea837c8 u0 com.android.launcher/com.android.launcher2.Launcher}] windowType=2 hidden=true hasVisible=true ... WindowToken{4eb1fd48 android.os.BinderProxy@4eae8a5c}: windows=[Window{4ea92b78 u0 PopupWindow:4ea0240c}] //对话框 windowType=-1 hidden=false hasVisible=false AppWindowToken{4eb5d6c0 token=Token{4ea35074 ActivityRecord{4ea68590 u0 jackpal.androidterm/.Term}}}: windows=[Window{4eb314e4 u0 jackpal.androidterm/jackpal.androidterm.Term}] windowType=2 hidden=false hasVisible=true app=true
在Android中,Window与Surface一一对应。 如果说Window关心的是层次和布局,是从设计者角度定义的类,Surface则从实现角度出发,是工程师关系和考虑的类。Window的内容是变化 的,Surface需要有空间来记录每个时刻Window的内容。在Android的SurfaceFlinger实现里,通常一个Surface有两块 Buffer, 一块用于绘画,一块用于显示,两个Buffer按照固定的频率进行交换,从而实现Window的动态刷新。
Layer是SurfaceFlinger 进行合成的基本操作单元。Layer在应用请求创建Surface的时候在SurfaceFlinger内部创建,因此一个Surface对应一个 Layer, 但注意,Surface不一定对应于Window,Android中有些Surface并不跟某个Window相关,而是有程序直接创建,比如说 StrictMode, 一块红色的背景,用于提示示Java代码中的一些异常, 还有SurfaceView, 用于显示有硬件输出的视频内容等。
当多个Layer进行合成的时候,并不是整个Layer的空间都会被完全显示,根据这个Layer最终的显示效果,一个Layer可以被划分成很多的Region, Android SurfaceFlinger 定义了以下一些Region类型:
Android 系统支持多种显示设备,比如说,输出到手机屏幕,或者通过WiFi 投射到电视屏幕。Android用Display类来表示这样的设备。不是所有的Layer都会输出到所有的Display, 比如说,我们可以只将Video Layer投射到电视, 而非整个屏幕。LayerStack 就是为此设 计,LayerStack 是一个Display 对象的一个数值, 而类Layer里也有成员变量mLayerStack, 只有两者的mLayerStack 值相同,Layer才会被输出到给该Display设备。所以LayerStack 决定了每个Display设备上可以显示的Layer数目。
SurfaceFlinger的工作内容,就是定期检查所有Layer的参数更新(LayerStack等),计算新的DirtyRegion, 然后将结果推送给底层显示驱动进行显示。这里面有很多的细节,我们将在另外的章节专门研究。
上面描述的几个概念,均是针对于显示这个层面,更多是涉及到中下层模块,应用层并不参与也无需关心。对于应用而言,它关心的是如何将内容画出来。Canvas 是Java层定义的一个类,它对应与Surface上的某个区域并提供了很多的2D绘制函数(借助于底层的Skia或OpenGL)。应用只需通过 LockCanvas() 来获取一个Canvas对象,并调用它的绘画方法,然后 unLockCanvasAndPost()来通知底层将更新内容进行显示。当然,并不是所有应用程序都需要直接操作Canva, 事实上只有少量应用需要直接操作Canvas, Android提供了很多封装好的控件 Widget,应用只需提供素材,如文字,图片,属性等等,这些控件会调用Canvas提供的接口帮用户完成绘制工作。
SurfaceFlinger 是一个独立的Service, 它接收所有Window的Surface作为输入,根据ZOrder, 透明度,大小,位置等参数,计算出每个Surface在最终合成图像中的位置,然后交由HWComposer或OpenGL生成最终的显示Buffer, 然后显示到特定的显示设备上。
HWComposer 是 Andrid 4.0后推出的新特性,它定义一套HAL层接口,然后各个芯片厂商根据各种硬件特点来实现。它的主要工作是将SurfaceFlinger计算好的Layer的显示参数最终合成到一个显示Buffer上。注意的是,Surface Flinger 并非是HWComposer的唯一输入,有的Surface 不由Android的WindowManager 管理,比如说摄像头的预览输入Buffer, 可以有硬件直接写入,然后作为HWComposer的输入之一与SurfaceFlinger的输出做最后的合成。
OpenGL 是一个2D/3D图形库,需要底层硬件(GPU)和驱动的支持。在Android 4.0后,它取代Skia成为Android 的2D 绘图图形库,大部分的控件均改用它来实现,应用程序也可以直接调用OpenGl函数来实现复杂的图形界面。
Display 是Android 对输出显示设备的一个抽象,传统的Display 设备是手机上的LCD屏,在Andrid 4.1 后,Android 对SurfaceFlinger 进行了大量的改动,从而支持其他外部输入设备,比如HDMI, Wifi Display 等等。Display的输入是根据上面的LayerStack值进行过滤的所有Window的Surface, 输出是和显示设备尺寸相同的Buffer, 这个Buffer 最终送到了硬件的FB设备,或者HDMI设备,或者远处的Wifi Display Sink设备进行显示。输入到输出这条路径上有SurfaceFlinger, OpenGL 和 HWComposer。
有了上述概念的解析,对Android的GUI 系统应该有了一些模糊的认识,接下来我们将按下面的顺序将一步步深入其中的细节。
在这一章里,我们将试图解答下面几个问题:
在这一章里,我们将探讨:
按键是怎么从底层driver 传递到具体的窗口进行处理的?
全局键是怎么处理的?
ANR是如何产生的?又如何处理?
等等...