Android 4.4(KitKat)表格管理子系统 - 骨架

原文地址:http://blog.csdn.net/jinzhuojun/article/details/37737439


窗体管理系统是Android中的主要子系统之中的一个。它涉及到App中组件的管理,系统和应用窗体的管理和绘制等工作。因为其涉及模块众多,且与用户体验密切相关。所以它也是Android其中最为复杂的子系统之中的一个。一个App从启动到主窗体显示出来,须要AppActivityManagerServiceAMS)。WindowManagerServiceWMS),SurfaceFlingerSF)等几个模块相互合作。App负责业务逻辑,绘制自己的视图;AMS管理组件、进程信息和Activity的堆栈及状态等等;WMS管理Activity相应的窗体及子窗体,还有系统窗体等;SF用于管理图形缓冲区,将App绘制的东西合成渲染在屏幕上。以下分几个部分进行分析。

 

窗体管理系统的主要框架及各模块之间的通讯接口大体例如以下:


基于Binder的本地过程调用(LPC)让Android的模块间耦合度更低。结构更加清晰。每一个模块各司其职。并向其他模块提供接口。

进程和uid这些Linux中的机制对这些模块提供了天然的保护,使得系统更加鲁棒。模块之间常常使用C/S的结构,而Service本身也可能是使用其他ServiceClient。举例来说,假设Service的实现叫XXXManagerService。那一般它对Client提供接口IXXXManager,然后Client要用Service的时候便会申请一个叫BpXXXManager的代理对象。它是远端BnXXXManager本地对象在Client端的代理。代理对象BpXXManager实现了IXXXManager的全部接口,仅仅只是里面的函数都是壳子,仅仅负责參数的准备,然后就调用远端对象去运行。

远端的的BnXXXManager对象及其继承类是真正做事的,BnXXXManager继承自IXXXManager.Stub抽象类,实现了IXXXManager接口。

Stub就如其名字一样,是BnXXXManager的继承类在BnXXXManager中的“钩子”。通过调用这些接口便能够调用到远端的Service功能了。概念上类似远程gdb调试。host机上的gdbguest上的gdbserver相连以后,在host上敲命令会让gdbserver去运行。但感觉就像是在host本地运行一样。这儿的gdbserver就提供了类似于Stub的功能。

 

这样的远程调用模型的建立过程通常是分层次的。比方WindowManagerGlobal会与WMS进行连接,ViewRootImpl会与WMS中的Session进行连接。高层先与高层通信,同一时候帮助建立低层间的通信。然后低层与低层直接通信。

打个比方。张三是A部门的员工。他想要和B部门合作搞一个活动,他一般不会直接冲过去B部门挨个问的。所以他先和自己的主管李四说。我要和B部门合作,于是李四找到B部门的主管王五,说你出个人吧。于是王五和赵六说,你负责这事儿吧。并告诉了A部门主管李四。李四再告诉下属张三,赵六是B部门接口人,你以后直接和他联系吧。

于是张三和赵六以后就直接联系了。假设合作中有须要超越自己权限的操作。他们再向各自的主管申请。比方AppWMS的连接,首先会建立一个SessionWMS,之后就会通过IWindowSession接口与WMS中的Session直接通信。

还有比如WMSSF先创建SurfaceSession,当中会创建SurfaceComposerClient,訪问SurfaceComposerClient时会在SF中创建Client与之相应,这个Client实现了ISurfaceComposerClient接口,之后SurfaceComposerClient会通过该接口与SF中的Client直接通信。

 

看代码过程中,各个对象间的数量及相应关系常常让人混淆,以下列举了在普通情况下各对象之间的实体关系图。当中标色的是相应子系统中比較基础核心的类。


要注意的几点:1. App中能够没有Activity。也能够没有PhoneWindowDecorView,比方一个显示浮动窗体的Service

2. Task中的Activity能够来自不同进程,比方App执行过程中打开相机App拍照。

3. WindowState代表WMS中的一个窗体。这和App端的Window类是不一样的,虽然非常多时候一个Window类(即PhoneWindow)有一个相应的WindowState,但那不是绝对的。一个ActivityWMS中有相应的AppWindowToken,一个AppWindowToken又能够包括多个WindowState。由于除了主窗体外,还可能有子窗体和启动窗体。此外对于系统窗体,WindowState还可能不正确应AppWindowToken4.这里的Application指的是App端的一个进程,它不同于AndroidManifest.xml中的<application>标签。后者是配置文件里对组件的管理者,它和进程之间没有本质关系,通过android:process标签能够让同一个<application>下的组件跑在多个进程,也能够让多个<application>中的组件跑在同一个进程。所以假设是<application>定义的Application的话和ProcessRecord就是m:n的关系了。下面谈到Application都是指一个App的进程。


首先分析下App端的结构。

移动平台一般显示区域有限,要完毕一个工作往往不是一屏内容中能搞定的。所以Android中有了Activity的概念,让用户能够把相关的子内容放到单独的Activity中,然后通过IntentActivity间跳转。类似于浏览网页。点击链接跳转到还有一个网页。

这些同一交互过程中的一系列Activity成为一个Task。这些Activity执行在主线程ActivityThread中。Activity要展现出来的主视图是DecorView。它是一棵视图树。

ViewRootImpl负责管理这个视图树和与WMS交互。与WMS交互通过WindowManagerImplWindowManagerGlobalDecorView被包括在系统的通用窗体抽象类Window其中。视图相应的图形缓冲区由Surface管理。其中涉及到的基本的类包括以下几个:

Activity:描写叙述一个Activity,它是与用户交互的基本单元。

ActivityThread:每个App进程有一个主线程,它由ActivityThread描写叙述。它负责这个App进程中各个Activity的调度和运行,以及响应AMS的操作请求等。

ApplicationThreadAMSActivity通过它进行通信。对于AMS而言,ApplicationThread代表了App的主线程。简而言之,它是AMSActivityThread进行交互的接口。

注意ActivityThreadApplicationThread之间的关系并不像ActivityApplication。后者的关系是Application中包括了多个Activity。而前者ActivityThreadApplicationThread是同一个东西的两种"View"ApplicationThread是在AMS眼中的ActivityThread

ViewRootImpl:主要责任包含创建Surface,和WMS的交互和App端的UI布局和渲染。同一时候负责把一些事件发往Activity以便Activity能够截获事件。

每个加入到WMS中的窗体相应一个ViewRootImpl,通过WindowManagerGlobalWMS加入窗体时创建。大多数情况下,它管理Activity顶层视图DecorView。总得来说,它相当于MVC模型中的Controller

ViewRootImpl::W:用于向WMS提供接口,让WMS控制App端的窗体。它可看作是个代理,非常多时候会调用ViewRootImpl中的功能。这样的内嵌类的使用方法非常多,特别是这样的提供接口的代理类,如PhoneWindow::DecorView等。

Instrumentation:官方提供的Hook。主要用于測试。假设仅仅关注窗体管理流程的话能够先无视。

WindowManagerImplActivity中与窗体管理系统通信的代理类,实现类是WindowManagerGlobalWindowManagerGlobalApp中全局的窗体管理模块,因此是个Singleton

当中管理着该App中的ViewRootImplDecorView等结构,以有两个ActivityApp为例:


Window:每一个App尽管都能够做得各不同样。可是作为有大量用户交互的系统,窗体之间必需要有统一的交互模式,这样才干减小用户的学习成本。

这些共性比方title, action bar的显示和通用按键的处理等等。Window类就抽象了这些共性。另外。它定义了一组CallbackActivity通过实现这些Callback被调用来处理事件。注意要和在WMS中的窗体区分开来,WMS中的窗体更像是App端的View

PhoneWindowPhoneWindowWindow类的唯一实现,至少眼下是。这种设计下假设要加其他平台的Window类型更加方便。

每一个Activity会有一个PhoneWindow,在attachActivityThread时创建,保存在mWindow成员中

Context:执行上下文。ActivityService本质上都是一个ContextContext包括了它们作为执行实体的共性,如启动Activity,绑定Service,处理BroadcastReceiver等等。注意Application也会有ContextActivityContext是相应Activity的。Activity被杀掉(比方转屏后)后就变了。

所以要注意假设有生命周期非常长的对象有对ActivityContext的引用的话。转屏、返回这样的会引起Activity销毁的操作都会引起内存泄露。而ApplicationContext生命周期是和App进程一致的。关于Context的类结构图有以下的形式。Context是抽象类,定义了接口。ContextImplContext的实现类,包括了实现。而ContextWrapperContext的包装类。它把请求delegate给当中的ContextImpl类去完毕。ContextThemeWrapperContextWrapper的装饰类,它在ContextWrapper的基础上提供了自己定义的主题。这结构初看有点乱,但结合以下的Decorator模式就一目了然了。


Surface:这是在App端管理图形缓冲区的类,当中最重要的是图形缓冲区队列。经由WMSSF中得到IGraphicBufferProducer接口对象BufferQueue后。Surface便能够从该队列中queuedequeue图形缓冲区。SurfaceControlWMS中封装了Surface以及与SF的交互。CanvasSurface从字面意思上非常像,但前者事实上更确切地说不是“画布”,而是“画家”。

Surface中的图形缓冲区才是App的画布。

 

上面这些基本类之间的主要关系例如以下:


当中比較重要的三个类的PhoneWindowDecorViewViewRootImplPhoneWindowViewRootImpl都包括了mDecor成员,它类型为DecorView。描写叙述了Activity的根视图。它也是ViewRootimplPhoneWindow间的枢纽。类似的。PhoneWindow父类中的CallbackPhoneWindowActivity的枢纽,而ViewRootImpl::WViewRootImplWMS间的枢纽。DecorView依次继承自FrameLayoutViewGroupView,因此它本质上是一个View。仅仅是它是Activity最根部的View,它以下可能有非常多Subview

DecorView描写叙述App窗体视图,而它的更新是由ViewRootImpl来控制的。

粗糙点说的话,假设用MVC模型来说的话,前者是View,后者是Controller

ViewRootImpl中的内嵌类W就是给WMS通信的接口。

W的声明中有两个成员变量:mViewAncestormWindowSession。它一头连着App端的ViewRootImpl,一头连着WMS中的Session。且实现了IWindow的接口。

意味着它是AppWMS的桥梁。是WMS用来回调App端,让ViewRootImpl做事用的。举例来说。dispatchAppVisibility()的流程就是经过它来完毕的:WMS ->ViewRootImpl::W->ViewRootHandler->handleAppVisibility()->scheduleTraversals()

 

Activity创建完后须要attach到主线程上。在attach()过程中会创建Window(实际是PhoneWindow),然后把PhoneWindow中的mCallback设为Activity。在PhoneWindow中两个关键内嵌类CallbackDecorViewCallback连接了ActivityDecorView连接了ViewRootImpl。这样,当ViewRootImpl有事件传来时,便能够沿着ViewRootImpl->DecorView->Window.Callback->Activity这条路来通知Activity。如按键事件就是通过这条路来传达的。

 

Android里还能够找到非常多这样的使用内嵌类来实现远端代理的样例,这样的设计使得系统满足最小隔离原则,Client端该用到哪些接口就暴露哪些接口。注意这样的类的函数都是跑在Binder线程中的,所以当中不能调用非线程安全的函数,也不能直接操作UI控件,所以一般都是往主线程消息队列里丢一个消息让其异步运行。

 

接下来,看下一个Activity的启动过程。以Launcher中启动一个App为例。比方在Launcher中我们点了一个图标启动一个AppActivityLauncher里会运行:

Intent intent = new Intent("xxx"); 

startActivity(intent);

接下来的大体流程例如以下:


图比較大,抓大放小,看清里面的主要脉络就可以。AppAMS交互流程主要分下面几步:

1. 原App通知AMS要起一个新Activity

2. AMS创建对应数据结构,然后通知WMS创建对应数据结构,再通知原Activity暂停。

3. 原Activity暂停后通知AMS

4. AMS创建新App进程,新App创建好后attach到AMS。

AMS再通知新App创建Activity等对应数据结构。

 

流程上我们能够总结出模块间的异步工作模式:当一个模块要求还有一个模块做特定任务时。通常是先调用目标模块的scheduleXXX(),这时目标模块的Binder线程仅仅是向主线程发起一个异步请求。然后对方主线程在消息队列中被唤醒处理,运行处理函数handleXXX()。另外我们也注意到非常多函数都是带有Locked后缀。这说明出来混。一定要申明自己是不是线程安全的。

 

为了使系统中的策略更加灵活,easy替换,系统使用了一些设计模式将之从其他逻辑中解耦。

IPolicy是一个工厂类接口。Policy为它的详细实现类。

它负责创建一系列策略相关的对象,如makeNewWindow()创建PhoneWindow等。同一时候PolicyManager还使用了Strategy模式将Policy包装起来,这为策略的替换提供了便利,也使执行时更换策略成为可能。


尽管眼下为止貌似仅仅有一种针对“Phone”的策略,所以还没看到这样设计的优点。可是,一方面,或许将来在多合一的移动设备上,笔记本,平板什么的能够切换,那么Policy自然也须要动态切换。

Android里还有非常多把这样的Policy单独拎出来的样例,如WindowManagerPolicy类。还有一方面,Android作为一个框架,须要让各个厂商把Android用到自己的平台上更加easy适配。将来假设作为眼镜,车载。智能家电等等嵌入式设备的统一平台。假设将Policy与其他模块紧耦合,那这些个平台上的代码就会差异越来越大。越来越难维护。

 

以下以类图的方式详细看下各模块之间的通信关系:



图中AppAMS的交互通过Binder。使用了代理模式。从App调用AMS是通过ActivityManagerProxy代理对象,它是本地对象ActivityManagerNativeApp端的代理。实现了IActivityManager接口。提供了startActivity()这种AMS服务函数。而ActivityManagerNative的实现事实上就是AMS本身。

而从AMS调用App端用的是ApplicationThreadProxy代理对象。它实现了IApplicationThread接口,其相应的实现是ApplicationThreadNative本地对象。存在于App端,ApplicationThread是事实上现类。AMS能够通过它来向App发出如scheduleXXX这些个异步消息。

 

ActivityAMS中的相应物是ActivityRecord,在WMS中相应物为AppWindowTokenActivityRecord::Token能够看作ActivityRecord的一个远端句柄。在WMSApp中分别存于AppWindowTokenActivityClientRecord之中。ActivityThread中的mActivities存放了远程ActivityRecord::Token到本地ActivityClientRecord的映射,因为这个Token是全局唯一的。所以还能够用来作为HashMapKeyActivityRecord::Token实现了IApplicationToken

WMS要通知AMS窗体变化时,就是用的这个接口。

 

新启动的Activity的创建初始化主要是在handleLaunchActivity()中完毕的。handleLaunchActivity()的作用是载入指定的Activity并执行。这当中在App端主要是创建ActivityThreadActivityPhoneWindowDecorView等对象,并调用Activity生命周期中的onCreate()onResume()函数执行用户逻辑。正常点的ApponCreate里会调用setContentView设置主视图。

setContentView()里主要是调用了installDecor()。当中会设置窗体的通用元素。如title, action bar之类,还会把xml文件inflate成布局对象。


能够看到这时创建了DecorView。这便是Activity的主窗体的顶层视图。DecorView创建好后。handleResumeActivity()中会将它加入到WMS中去。当AppWMS加入窗体时。会调用WindowManagerImpladdView()。注意WindowManagerImpl中的addView()函数和ViewGroup里的addView()函数全然不一样,后者是将View加入到本地的View hierarchy中去,和WMS没有关系。addView()的流程例如以下:


首先通过WindowManagerImpladdView()会创建相应的ViewRootImpl,然后ViewRootImpl申请WMS得到Session(假设是App第一个Activity会新建),其接口为IWindowSession,然后ViewRootImpl通过addToDisplay()把自己的ViewRootImpl::W(实现了IWindow接口)注冊给WMS。这样,两方都有了对方的接口。WMS中的Session注冊到WindowManagerGlobal的成员WindowSession中,ViewRootImpl:W注冊到WindowState中的成员mClient中。前者是为了App改变View结构时请求WMS为其更新布局。后者代表了App端的一个加入到WMS中的View,每个像这样通过WindowManager接口中addView()加入的窗体都有一个相应的ViewRootImpl,也有一个相应的ViewRootImpl::W

它能够理解为是ViewRootImpl中暴露给WMS的接口,这样WMS能够通过这个接口和App端通信。Session建立好后,接下来就是通过ViewRootImplsetViewViewRootImpl中的W注冊到WMS中,WMS会创建相应数据结构,并将其插入内部维护的窗体堆栈,还会与SF建立Session以备将来为之创建SurfaceaddView()运行完后这个Activity的主视图就正式对WMS可见了。总结来说。addView()的工作主要包含创建ViewRootImpl,和远程WMS建立Session,并将当前视图注冊到WMS这几步。

能够看到App端通过WindowManagerGlobal调用addView(),调用链到WMS就变成addWindow(),概念发生了改变,这也印证上面提到的App端和WMS端的Window概念不一样的说法。

 

从以上Activity启动的整个流程能够看到,窗体的加入和管理须要AMSWMS两个Service的配合。

以下看看AMSWMS的主要作用和结构。

 

AMSActivityManagerService

Activity的管理者。

事实上除了ActivityAMS也管Service等组件信息。另外AMS还管理Process信息。以下是AMS几个重要数据结构:

ActivityRecord:描写叙述单个ActivityActivity堆栈中的基本单元。

ActivityRecord::Token:相应ActivityRecordIBinder对象,能够看作远程对象的本地句柄。可用于LPC,又可用来作映射中的unique ID。常常是两用的。

ProcessRecord:描写叙述一个App进程。包括了该进程中的ActivityService列表。

TaskRecordTaskRecord中的mActivitiesActivityRecord的列表,它们是依照历史顺序排序的。

ActivityStackActivity堆栈,当中的ActivityRecord是通过TaskRecord这一层间接地被管理着。

ActivityStackSupervisorActivityStackSupervisorActivityStack的总管。

4.4中默认引入了两个ActivityStack。一个叫Home stack。放Launchersystemuiid0;还有一个是Applicationstack,放AppActivityid可能是随意值。定义例如以下:

137    /** The stack containing the launcher app*/
138    private ActivityStack mHomeStack;
 
145    /** All the non-launcher stacks */
146    private ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
 

系统中的Activity堆栈信息能够通过dumpsys activity命令查看:

$ adb shell am stackboxes
Box id=3 weight=0.0vertical=false bounds=[0,0][1280,736]
Stack=
  Stack id=3 bounds=[0,0][1280,736]
    taskId=6:com.example.android.apis/com.example.android.apis.ApiDemos
    taskId=7:com.android.camera/com.android.camera.Camera
 
Box id=0 weight=0.0vertical=false bounds=[0,0][1280,736]
Stack=
  Stack id=0 bounds=[0,0][1280,736]
    taskId=3:com.android.launcher/com.android.launcher2.Launcher


dump信息能够看出。这大致是一个层级结构。从上到下依次是Stack->Task->Activity的结构。Stack放在ActivityStackSupervisor中的mStacks。它是一个列表,元素类型为ActivityStack。因此,基本元素ActivityRecord是以层级的结构被AMS管理起来的:


为什么引入了Task的概念呢?首先看下Task的官方定义“A task (from the activity that started it to the next task activity)defines an atomic group of activities that the user can move to.”。Task是为了完毕一个功能的一系列相关的有序Activity集合。能够理解为用户与App之间对于特定功能的一次会话。一个Task中的Activity能够来自不同的App。比方在邮件App中须要看图片附件,然后会开imageviewActivity来显示它。依据不用的业务逻辑。我们会在启动ActivityIntent中设不同的FLAGFLAG_ACTIVITY_NEW_TASKFLAG_ACTIVITY_MULTIPLE_TASK等),这些FLAG的处理中会对Task的处理,进而对Activity的调度产生影响。详细的FLAG可參见/frameworks/base/core/java/android/content/Intent.java。关于Task的官方介绍http://developer.android.com/guide/components/tasks-and-back-stack.html

 

总得来说。上面这些个数据结构之间的关系例如以下


WMSWindowManagerService

窗体的管理者。

AMS不同,一些高层的App中的概念,如进程等,WMS是不care的。

由于WMS仅仅对窗体进行管理。哪个进程的它不关心。像Activity这些概念在WMS仍然有,由于Activity对窗体的管理会产生影响。

WMS主要责任是维护窗体堆栈。计算每一个窗体的layer信息交给SF,替App申请和调整画图Surface,当窗体显示状态变化了还要通知其他模块,另外还要处理系统输入。所以说,WMS可能是与其他模块交互最多的模块之中的一个了。它与AMSAppSFInput等模块都交集。说到窗体管理,首先看一下Android中有哪些窗体。Android中大体有下面几种窗体类型:1.应用窗体,一般来说就是Activity的主窗体。但也有些情况App没有Activity,直接把自己定义的View加入到WMS中。比方浮动窗体。2.子窗体,须要有一个父窗体,如Context MenuOption MenuPopup WindowDialog等。

3.系统窗体。如状态栏,锁屏窗体,输入法窗体,壁纸窗体和Toast之流。由系统创建的,不依赖于父窗体。

 

WMS中涉及到的主要数据结构有这么几个:

WindowStateWMS中最主要的元素,描写叙述WMS中的一个窗体。它既能够是由App加入过来的View,也能够是系统创建的系统窗体。

mAttrsWindowManager.LayoutParams类型,描写叙述布局參数。mClientIWindow类型,也就是App端的ViewRootImpl::W

为了查找方便,WMS中的mWindowMap保存了IWindowWindowState的映射,mTokenMap保存了IApplicationTokenWindowToken的映射。

SessionApp提供IWindowSession接口让其能够和WMS通信。AppWMS有一个Session对象App就是通过这个Session来向WMS发出窗体管理申请的。

命令dumpsys window sessions能够查看系统中的Session

WINDOW MANAGERSESSIONS (dumpsys window sessions)
  Session Session{b32d7d68 1404:u0a10008}:
    mNumWindow=1 mClientDead=falsemSurfaceSession=android.view.SurfaceSession@b31adc20
  Session Session{b32dd278 1326:u0a10007}:
    mNumWindow=5 mClientDead=falsemSurfaceSession=android.view.SurfaceSession@b327b348
  Session Session{b3290f68 1275:1000}:
    mNumWindow=1 mClientDead=falsemSurfaceSession=android.view.SurfaceSession@b30a3890

SurfaceSessionWMSSF之间的会话。

每一个App会在WMS中有一个相应的SurfaceSession,也会有一个相应的SurfaceComposerClient

用于向SF申请和设置图形缓冲区等。

WindowToken: 描写叙述WM一组相关的窗体。这些Window相应的WindowState放在其成员变量windows里。

其主要继承类AppWindowToken,它是针对AppWindowToken结构。WindowState中的mAppToken指向所属的AppWindowToken,假设是系统窗体,mAppToken为空,mToken指向WindowToken对象。

命令dumpsys window tokens用于查看WindowToken和AppWindowToken信息:

WINDOW MANAGERTOKENS (dumpsys window tokens)
  All tokens:
  WindowToken{b32921e8 null}:
    windows=[Window{b333cd40 u0 SearchPanel},Window{b328d920 u0 Keyguard}, Window{b32961d8 u0 NavigationBar},Window{b32c6aa0 u0 StatusBar}, Window{b3292288 u0 KeyguardScrim}]
    windowType=-1 hidden=false hasVisible=true
  WindowToken{b3260980android.os.Binder@b3269d60}:
    windows=[Window{b325c180 u0com.android.systemui.ImageWallpaper}]
    windowType=2013 hidden=falsehasVisible=true
  AppWindowToken{b322a358 token=Token{b3287ea0ActivityRecord{b3287c28 u0 com.android.launcher/com.android.launcher2.Launchert1}}}:
    windows=[Window{b328b0c0 u0com.android.launcher/com.android.launcher2.Launcher}]
    windowType=2 hidden=false hasVisible=true
    app=true
    allAppWindows=[Window{b328b0c0 u0com.android.launcher/com.android.launcher2.Launcher}]
    groupId=1 appFullscreen=truerequestedOrientation=-1
    hiddenRequested=false clientHidden=falsewillBeHidden=false reportedDrawn=true reportedVisible=true
    numInterestingWindows=1 numDrawnWindows=1inPendingTransaction=false allDrawn=true (animator=true)
    startingData=null removed=falsefirstWindowDrawn=true
  WindowToken{b32b81c0android.os.Binder@b3228950}:
    windows=[]
    windowType=2011 hidden=falsehasVisible=false
 
  Wallpaper tokens:
  Wallpaper #0 WindowToken{b3260980android.os.Binder@b3269d60}:
    windows=[Window{b325c180 u0com.android.systemui.ImageWallpaper}]
    windowType=2013 hidden=falsehasVisible=true

AppWindowToken每一个AppActivity相应一个AppWindowToken。当中的appTokenIApplicationToken类型,连接着相应的AMS中的ActivityRecord::Token对象,有了它就能够顺着AppWindowToken找到AMS中相应的ActivityRecord。当中allAppWindows是一个无序的列表。包括该Activity中全部的窗体。用dumpsys window display能够查看z-orderedAppWindowToken列表:

  Application tokens in Z order:
  App #4 AppWindowToken{b31c2128token=Token{b3235c98 ActivityRecord{b324c8a0 u0com.example.android.apis/.view.PopupMenu1 t9}}}:
    windows=[Window{b32a5eb8 u0com.example.android.apis/com.example.android.apis.view.PopupMenu1}]
    windowType=2 hidden=false hasVisible=true
    app=true
   allAppWindows=[Window{b32a5eb8 u0com.example.android.apis/com.example.android.apis.view.PopupMenu1},Window{b32eb6f0 u0 PopupWindow:b2ff5368}]
    groupId=9 appFullscreen=truerequestedOrientation=-1
    hiddenRequested=false clientHidden=falsewillBeHidden=false reportedDrawn=true reportedVisible=true
    numInterestingWindows=2 numDrawnWindows=2inPendingTransaction=false allDrawn=true (animator=true)
    startingData=null removed=falsefirstWindowDrawn=true
  App #3 AppWindowToken{b3429e18token=Token{b31c5e58 ActivityRecord{b31e8ff0 u0com.example.android.apis/.ApiDemos t9}}}:
    windows=[Window{b32a39f8 u0com.example.android.apis/com.example.android.apis.ApiDemos}]
    windowType=2 hidden=true hasVisible=true
    app=true
    allAppWindows=[Window{b32a39f8 u0com.example.android.apis/com.example.android.apis.ApiDemos}]
    groupId=9 appFullscreen=truerequestedOrientation=-1
    hiddenRequested=true clientHidden=truewillBeHidden=false reportedDrawn=false reportedVisible=false
    numInterestingWindows=1 numDrawnWindows=1inPendingTransaction=false allDrawn=true (animator=true)
    startingData=null removed=falsefirstWindowDrawn=true
  App #2 AppWindowToken{b32ccde0token=Token{b333d128 ActivityRecord{b32dcf10 u0com.example.android.apis/.ApiDemos t9}}}:
    windows=[Window{b320fd28 u0com.example.android.apis/com.example.android.apis.ApiDemos}]
    windowType=2 hidden=true hasVisible=true
    app=true
    allAppWindows=[Window{b320fd28 u0com.example.android.apis/com.example.android.apis.ApiDemos}]
    groupId=9 appFullscreen=truerequestedOrientation=-1
    hiddenRequested=true clientHidden=truewillBeHidden=false reportedDrawn=false reportedVisible=false
    numInterestingWindows=1 numDrawnWindows=1inPendingTransaction=false allDrawn=true (animator=true)
    startingData=null removed=falsefirstWindowDrawn=true
  App #1 AppWindowToken{b321ff58token=Token{b321d860 ActivityRecord{b321d990 u0com.android.launcher/com.android.launcher2.Launcher t1}}}:
    windows=[Window{b3268018 u0com.android.launcher/com.android.launcher2.Launcher}]
    windowType=2 hidden=true hasVisible=true
    app=true
    allAppWindows=[Window{b3268018 u0com.android.launcher/com.android.launcher2.Launcher}]
    groupId=1 appFullscreen=truerequestedOrientation=-1
    hiddenRequested=true clientHidden=truewillBeHidden=false reportedDrawn=false reportedVisible=false
    numInterestingWindows=1 numDrawnWindows=1inPendingTransaction=false allDrawn=true (animator=true)
    startingData=null removed=falsefirstWindowDrawn=true

注意AppWindowToken是相应Activity的,WindowState是相应窗体的。所以AppWindowTokenWindowState1:n的关系。举例来说。上面第一项AppWindowToken。它包括了PopupWindow子窗体,所以有相应两个WindowState。一般地说。一个Activity可能包括多个窗体。如启动窗体,PopupWindow等,这些窗体在WMS就会组织在一个AppWindowToken中。AppWindowTokenWindowState间的从属结构及WindowState间的父子结构能够通过下面成员表示。


Task上面提到AppWindowToken保存了属于它的WindowState的有序列表,而它本身也作为一个列表被管理在TaskStack中的mTasks成员中,而且是按历史顺序存放的,最老的Task在最底下。

结合前面的AppWindowTokenWindowState之间的关系,能够了解到它们是以这样一个层级的关系组织起来的:


这个结构是不是非常眼熟。AMS里也有类似的结构。WMS里的TaskStack,相应前面AMS中的ActivityStack,这两者及其子结构会保持同步。从中我们能够发现。WMSAMS中的数据结构是有相应关系的。如AMS中的TaskRecordWMS中的TaskAMS中的ActivityRecordWMS中的AppWindowToken。另外WMSTaskStackmTasks须要和AMSActivityStackmTaskHistory顺序保持一致。


DisplayContent:表示一个显示设备上的内容,这个显示设备能够是外接显示屏,也能够是虚拟显示屏。当中mWindows是一个WindowState的有序(Z-ordered,底部最先)列表。

mStackBoxes包括了若干个StackBox,当中一个为HomeStack。还有一个是AppStackBox。全部的StackBox被组织成二叉树,StackBox是当中的节点。当中有三个重要成员变量,mFirstmSecond指向左和右子结点(也是StackBox),StackBox的成员mStack才是我们真正关心的东西-TaskStack。能够看到,为了要把TaskStack存成树的结构。须要一个容器,这个容器就是StackBoxDisplayContentStackBoxTaskStack的关系例如以下:


StackBox信息能够用am stack boxesdumpsys window displays命令查看:

$ adb shell am stackboxes
WARNING: linker:libdvm.so has text relocations. This is wasting memory and is a security risk.Please fix.
Box id=2 weight=0.0vertical=false bounds=[0,33][800,1216]
Stack=
  Stack id=2 bounds=[0,33][800,1216]
    taskId=3:com.android.contacts/com.android.contacts.activities.PeopleActivity
 
Box id=0 weight=0.0vertical=false bounds=[0,33][800,1216]
Stack=
  Stack id=0 bounds=[0,33][800,1216]
    taskId=1:com.android.launcher/com.android.launcher2.Launcher
      mStackId=2
      {taskId=3appTokens=[AppWindowToken{b3332498 token=Token{b33006c0 ActivityRecord{b32ecbb0u0 com.android.contacts/.activities.PeopleActivity t3}}}]}

上面是正常情况下的,用am stack create命令能够创建分屏窗体(详见http://androidinternalsblog.blogspot.com/2014/03/split-screens-in-android-exist.html),如:

$ adb shell am stackcreate 7 3 0 0.5
createStack returnednew stackId=4

然后再查看stack信息就变成了这样:

$ adb shell am stackboxes
Box id=3 weight=0.5vertical=false bounds=[0,0][1280,736]
First child=
  Box id=4 weight=0.0 vertical=falsebounds=[0,0][640,736]
  Stack=
    Stack id=4 bounds=[0,0][640,736]
      taskId=7:com.android.camera/com.android.camera.Camera
Second child=
  Box id=5 weight=0.0 vertical=falsebounds=[640,0][1280,736]
  Stack=
    Stack id=3 bounds=[640,0][1280,736]
      taskId=6:com.example.android.apis/com.example.android.apis.ApiDemos
 
Box id=0 weight=0.0vertical=false bounds=[0,0][1280,736]
Stack=
  Stack id=0 bounds=[0,0][1280,736]
    taskId=3:com.android.launcher/com.android.launcher2.Launcher

可见,在分屏情况下。这个结构以二叉树的形式分裂,形成这种结构:


除了TaskStackDisplayContent中的成员mTaskHistory也包括了一个有序的Task列表。

结合上面几个概念,能够得到以下的关系:


逻辑上,一个TaskTask)能够包括多个Activity(相应AppWindowToken),每一个Activity能够包括多个窗体(相应WindowState),而每一个窗体都是可能被放在随意一个显示屏上的(想象一个Windows操作系统中外接显示器的情况)。因此就有了上面这个结构。从这个结构能够看出。WMS的主要任务之中的一个就是维护各窗体的Z-order信息。Z轴可看作是屏幕法向量方向上的坐标轴,值越大的层意味着离用户越近,会把值小的窗体给盖住。一方面。WMS须要知道各窗体的遮挡关系来做layout和分配释放Surface,还有一方面,这个Z-order信息会转化为窗体相应Surfacelayer属性输出到SF,指导SF的渲染。

那么,这个列表是怎么管理的呢?我们知道,每一个窗体在WMS都有相应的WindowState,因此。本质上我们须要维护一个Z-order排序的WindowState列表。首先,TaskStack中包括了历史序的Task。每一个Task又包括了Z-orderedAppWindowTokenAppWindowToken的成员windows又包括了一个Z-orderedWindowState列表。前面提到过,一个AppWindowToken相应AMS中的一个ActivityRecord,因此这个列表包括了这个Activity中的全部窗体,子窗体,開始窗体等。还有一方面。DisplayContent中也有一个成员mWindows,指向一个Z-orderedWindowState列表(列队越前面的在越底部),它描写叙述的是单个显示屏上的窗体集合。在加入窗体时会通过addAppWindowToListLocked()函数往这个窗体堆栈插入元素。

因为插入过程要考虑子窗体,開始窗体等的偏移量,往DisplayContentmWindows插入元素时需考虑WindowToken中的windows列表。

得到DisplayContent中的mWindows列表后,之后会调用assignLayersLocked()来依据这个Z-order列表信息得到每一个窗体的layer值。WindowState的列表能够用dumpsys window windows命令查看

WINDOW MANAGERWINDOWS (dumpsys window windows)
  Window #7 Window{b32b2110 u0 SearchPanel}:
    mDisplayId=0 mSession=Session{b32369b81326:u0a10007} mClient=android.os.BinderProxy@b3222788
    mOwnerUid=10007 mShowToOwnerOnly=falsepackage=com.android.systemui appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillxfill)gr=#800053 sim=#31 ty=2024 fl=#1820100 fmt=-3 wanim=0x10301f5}
    Requested w=800 h=1216 mLayoutSeq=37
    mHasSurface=falsemShownFrame=[0.0,0.0][0.0,0.0] isReadyForDisplay()=false
    WindowStateAnimator{b32f06d8 SearchPanel}:
      mShownAlpha=0.0 mAlpha=1.0 mLastAlpha=0.0
...
  Window #2 Window{b3282e18 u0com.example.android.apis/com.example.android.apis.ApiDemos}:
    mDisplayId=0 mSession=Session{b32cfba03137:u0a10045} mClient=android.os.BinderProxy@b31faaf8
    mOwnerUid=10045 mShowToOwnerOnly=truepackage=com.example.android.apis appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillxfill)sim=#110 ty=1 fl=#1810100 pfl=0x8 wanim=0x10302f5}
    Requested w=800 h=1216 mLayoutSeq=82
    mHasSurface=truemShownFrame=[0.0,0.0][800.0,1216.0] isReadyForDisplay()=true
    WindowStateAnimator{b32df438com.example.android.apis/com.example.android.apis.ApiDemos}:
      Surface: shown=true layer=21010 alpha=1.0rect=(0.0,0.0) 800.0 x 1216.0
...

总结一下,WMS服务端的类结构图:



设计中比較灵活的一个地方是当中的WindowManagerPolicy这个类。它採用了Strategy模式。将策略相关的部分抽象出来,用PhoneWindowManager实现。它也是前面提到的Policy工厂模式的一部分。

尽管如今PhoneWindowManager是唯一的继承类。这样的结构看似可有可无,但假设以后厂商要加其他的策略,或更改已有策略,这样的设计就行提供良好的灵活性。

 

以上就是AMSWMS的大体框架。粗糙地说,AMS管理ActivityServiceProcess等信息。WMS管理应用和系统窗体。这两者既有联系又有非常大不同。Activity一般有窗体。Service能够有也能够没有窗体,而窗体不一定非要相应Activity或者Service。仅仅是非常多时候一个Activity中就一个顶层视图。相应WMS一个窗体,所以会给人一一相应的错觉,但这两者事实上没有直接关系。这就造就了AMSWMS两大模块,尽管当中数据结构有非常多是保持同步的,可是设计上让它们分开,各司其职。异步工作。

从窗体管理的流程来说,App负责视图树的管理和业务逻辑。AMS管理和调度全部App中的组件,通知WMS组件的状态信息。

WMSAppSF申请和调整Surface,同一时候计算维护窗体的布局,z-order等信息,另外当显示状态发生变化时。WMS还要通知App作出调整。SFWMS拿到各窗体相应Surface的属性和layer信息,同一时候从App拿到渲染好的图形缓冲区。进行进一步的合并渲染。放入framebuffer,最后用户就能在屏幕上看到App的窗体了。


版权声明:本文博主原创文章。博客,未经同意不得转载。

posted @ 2015-09-25 14:51  phlsheji  阅读(591)  评论(0编辑  收藏  举报