zoukankan      html  css  js  c++  java
  • 图解Android

    http://www.cnblogs.com/samchen2009/p/3364327.html

    Android的GUI系统是Android最重要也最复杂的系统之一。它包括以下部分:

    1. 窗口和图形系统 - Window and View Manager System.
    2. 显示合成系统 - Surface Flinger
    3. 用户输入系统 - InputManager System
    4. 应用框架系统 - Activity Manager System.

    它们之间的关系如下图所示

    只有对这些系统的功能和工作原理有基本的了解,我们才能够解答一些经常萦绕在脑海里的问题,比如说:

    1. Activity启动过程是怎样的?Activity的onXXX()在后台都做了什么工作?Activity的show()和hide()是如何控制的?
    2. Surface是什么时候被谁创建的?
    3. Android是如何把一个个的控件画到Surface上的?然后显示到手机屏幕上的?
    4. 应用程序窗口是如何获取焦点的?用户的按键(触摸屏或键盘)是怎样传递到当前的窗口?
    5. Android是一个多窗口的系统吗?
    6. Android是怎么支持多屏互动的?(Wifi Display)
    7. 输入法窗口到底属于哪个进程?为什么不管什么应用,只要有输入框的地方都能弹出它?

    本文将从框架和流程角度出发,试图对Android的GUI系统做一个简要但全面的介绍,希望借此能够帮助大家找到上述问题的答案。

    所有的内容可以浓缩在下面这张图里,里面有很多的名称和概念我们需要事先解释一下:

    1. Window, PhoneWindow 和 Activity

    • Activity 是 Android 应用的四大组件之一 (Activity, Service,  Content Provider,  Broadcast Receiver), 也是唯一一个与用户直接交互的组件。
    • Window 在 不同的地方有着不同的含义。在Activity里,Window 是一个抽象类,代表了一个矩形的不可见的容器,里面布局着若干个可视的区域(View). 每个Activity都会有一个Window类成员变量,mWindow. 而在WindowManagerService里,Window指的是WindowState对象,从图中可以看出,WindowState与一个 ViewRootImpl里的mWindow对象相对应。所以说,WindowManagerService里管理的Window其实是 Acitivity的ViewRoot。我们下面提到的Window,如果没有做特殊说明,均指的是WindowManagerService里的 ‘Window' 概念,即一个特定的显示区域。从用户角度来看,Android是个多窗口的操作系统,不同尺寸的窗口区域根据尺寸,位置,z-order及是否透明等参数 叠加起来一起并最终呈现给用户。这些窗口既可以是来自一个应用,也可以来自与多个应用,这些窗口既可以显示在一个平面,也可以是不同的平面。总而言之,窗 口是有层次的显示区域,每个窗口在底层最终体现为一个个的矩形Buffer, 这些Buffer经过计算合成为一个新的Buffer,最终交付Display系统进行显示。为了辅助最后的窗口管理,Android定义了一些不同的窗 口类型:
      • 应用程序窗口 (Application Window): 包括所有应用程序自己创建的窗口,以及在应用起来之前系统负责显示的窗口。
      • 子窗口(Sub Window):比如应用自定义的对话框,或者输入法窗口,子窗口必须依附于某个应用窗口(设置相同的token)。
      • 系 统窗口(System Window): 系统设计的,不依附于任何应用的窗口,比如说,状态栏(Status Bar), 导航栏(Navigation Bar), 壁纸(Wallpaper), 来电显示窗口(Phone),锁屏窗口(KeyGuard), 信息提示窗口(Toast), 音量调整窗口,鼠标光标等等。
    • PhoneWindow 是Activity Window的扩展,是为手机或平板设备专门设计的一个窗口布局方案,就像大家在手机上看到的,一个PhoneWindow的布局大致如下:

                

    2. View, DecorView, ViewGroup, ViewRoot

    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).

    3. ViewRootImple,  WindowManagerImpl,  WindowManagerGlobals

    WindowManagerImpl: 实现了WindowManager 和 ViewManager的接口,但大部分是调用WindowManagerGlobals的接口实现的。

    WindowManagerGlobals: 一个SingleTon对象,对象里维护了三个数组:

    • mRoots[ ]: 存放所有的ViewRootImpl
    • mViews[ ]: 存放所有的ViewRoot
    • mParams[ ]: 存放所有的LayoutParams.

        同时,它还维护了两个全局IBinder对象,用于访问WindowManagerService 提供的两套接口:

    • IWindowManager:  主要接口是OpenSession(), 用于在WindowManagerService 内部创建和初始化Session, 并返回IBinder对象。
    • ISession:  是Activity Window与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。

    4. WindowManager, WindowManagerService 和 WindowManagerPolicyService

    WindowManager:  是一个接口类,定义了一些接口来管理Acitivity里的窗口。WindowManager 是Android应用进程空间里的一个对象,不提供IPC服务。

    WindowManagerService: 是SystemServer进程里的一个Service,它的主要功能有

    • 窗 口的显示刷新。这里的'Window' 其实是ViewRoot, 和上面WindowManager管理的'Window' 是不一样的,前者是实实在在要进行显示的‘窗口’, 而后者只是一个View的容器,并不会显示出来。大部分情况下,Android同时只有一个Activity工作,但这并不意思着只有一个Window被 显示,Android可能会同时显示来自相同或不同应用的多个Window,比如说,屏幕的上方有一个状态栏,最下方有一个导航栏,有时会弹出一些对话 框,背景可能会显示墙纸,在应用启动过程中,会有动画效果,这个时候两个Activity的窗口会有所变形且同时显示出来,这一切都需要 WindowManager来控制何时,何地,以何种方式将所有的窗口整合在一起显示。
    • 预处理用户输入时间(GlobalKey? SystemKey), 并分发给合适的窗口进行处理。
    • 输出显示(Display)管理。包括WifiDisplay.

    WindowManagerService 是Android Framework里最为庞大复杂的模块之一,我们后面会从各个方面对它进行尽可能详细的分析。 

    5. Token, WindowToken, AppWindowToken, ApplicationToken, appToken

    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
    复制代码

    6. Surface, Layer 和 Canvas, SurfaceFlinger, Region, LayerStack

    在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类型:

    •  TransparantRegion: 完全透明的区域,在它之下的区域将被显示出来。
    •  OpaqueRegion: 完全不透明的区域,是否显示取决于它上面是否有遮挡或是否透明。
    •  VisibleRegion: 可见区域,包括完全不透明无遮挡区域或半透明区域。 visibleRegion = Region - above OpaqueRegion.
    •  CoveredRegion: 被遮挡区域,在它之上,有不透明或半透明区域。
    •  DirtyRegion: 可见部分改变区域,包括新的被遮挡区域,和新的露出区域。

    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提供的接口帮用户完成绘制工作。

    7. SurfaceFlinger, HWComposer, OpenGL 和 Display

    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 系统应该有了一些模糊的认识,接下来我们将按下面的顺序将一步步深入其中的细节。

  • 相关阅读:
    Read-Copy Update Implementation For Non-Cache-Coherent Systems
    10 华电内部文档搜索系统 search04
    10 华电内部文档搜索系统 search05
    lucene4
    10 华电内部文档搜索系统 search01
    01 lucene基础 北风网项目培训 Lucene实践课程 索引
    01 lucene基础 北风网项目培训 Lucene实践课程 系统架构
    01 lucene基础 北风网项目培训 Lucene实践课程 Lucene概述
    第五章 大数据平台与技术 第13讲 NoSQL数据库
    第五章 大数据平台与技术 第12讲 大数据处理平台Spark
  • 原文地址:https://www.cnblogs.com/feng9exe/p/5719412.html
Copyright © 2011-2022 走看看