Android 4.4(KitKat)表格管理子系统 - 骨架
原文地址:http://blog.csdn.net/jinzhuojun/article/details/37737439
窗体管理系统是Android中的主要子系统之中的一个。它涉及到App中组件的管理,系统和应用窗体的管理和绘制等工作。因为其涉及模块众多,且与用户体验密切相关。所以它也是Android其中最为复杂的子系统之中的一个。一个App从启动到主窗体显示出来,须要App。ActivityManagerService(AMS)。WindowManagerService(WMS),SurfaceFlinger(SF)等几个模块相互合作。App负责业务逻辑,绘制自己的视图;AMS管理组件、进程信息和Activity的堆栈及状态等等;WMS管理Activity相应的窗体及子窗体,还有系统窗体等;SF用于管理图形缓冲区,将App绘制的东西合成渲染在屏幕上。以下分几个部分进行分析。
窗体管理系统的主要框架及各模块之间的通讯接口大体例如以下:
基于Binder的本地过程调用(LPC)让Android的模块间耦合度更低。结构更加清晰。每一个模块各司其职。并向其他模块提供接口。
进程和uid这些Linux中的机制对这些模块提供了天然的保护,使得系统更加鲁棒。模块之间常常使用C/S的结构,而Service本身也可能是使用其他Service的Client。举例来说,假设Service的实现叫XXXManagerService。那一般它对Client提供接口IXXXManager,然后Client要用Service的时候便会申请一个叫BpXXXManager的代理对象。它是远端BnXXXManager本地对象在Client端的代理。代理对象BpXXManager实现了IXXXManager的全部接口,仅仅只是里面的函数都是壳子,仅仅负责參数的准备,然后就调用远端对象去运行。
远端的的BnXXXManager对象及其继承类是真正做事的,BnXXXManager继承自IXXXManager.Stub抽象类,实现了IXXXManager接口。
Stub就如其名字一样,是BnXXXManager的继承类在BnXXXManager中的“钩子”。通过调用这些接口便能够调用到远端的Service功能了。概念上类似远程gdb调试。host机上的gdb和guest上的gdbserver相连以后,在host上敲命令会让gdbserver去运行。但感觉就像是在host本地运行一样。这儿的gdbserver就提供了类似于Stub的功能。
这样的远程调用模型的建立过程通常是分层次的。比方WindowManagerGlobal会与WMS进行连接,ViewRootImpl会与WMS中的Session进行连接。高层先与高层通信,同一时候帮助建立低层间的通信。然后低层与低层直接通信。
打个比方。张三是A部门的员工。他想要和B部门合作搞一个活动,他一般不会直接冲过去B部门挨个问的。所以他先和自己的主管李四说。我要和B部门合作,于是李四找到B部门的主管王五,说你出个人吧。于是王五和赵六说,你负责这事儿吧。并告诉了A部门主管李四。李四再告诉下属张三,赵六是B部门接口人,你以后直接和他联系吧。
于是张三和赵六以后就直接联系了。假设合作中有须要超越自己权限的操作。他们再向各自的主管申请。比方App与WMS的连接,首先会建立一个Session到WMS,之后就会通过IWindowSession接口与WMS中的Session直接通信。
还有比如WMS和SF先创建SurfaceSession,当中会创建SurfaceComposerClient,訪问SurfaceComposerClient时会在SF中创建Client与之相应,这个Client实现了ISurfaceComposerClient接口,之后SurfaceComposerClient会通过该接口与SF中的Client直接通信。
看代码过程中,各个对象间的数量及相应关系常常让人混淆,以下列举了在普通情况下各对象之间的实体关系图。当中标色的是相应子系统中比較基础核心的类。
要注意的几点:1. App中能够没有Activity。也能够没有PhoneWindow和DecorView,比方一个显示浮动窗体的Service。
2.
Task中的Activity能够来自不同进程,比方App执行过程中打开相机App拍照。
3.
WindowState代表WMS中的一个窗体。这和App端的Window类是不一样的,虽然非常多时候一个Window类(即PhoneWindow)有一个相应的WindowState,但那不是绝对的。一个Activity在WMS中有相应的AppWindowToken,一个AppWindowToken又能够包括多个WindowState。由于除了主窗体外,还可能有子窗体和启动窗体。此外对于系统窗体,WindowState还可能不正确应AppWindowToken。4.这里的Application指的是App端的一个进程,它不同于AndroidManifest.xml中的<application>标签。后者是配置文件里对组件的管理者,它和进程之间没有本质关系,通过android:process标签能够让同一个<application>下的组件跑在多个进程,也能够让多个<application>中的组件跑在同一个进程。所以假设是<application>定义的Application的话和ProcessRecord就是m:n的关系了。下面谈到Application都是指一个App的进程。
首先分析下App端的结构。
移动平台一般显示区域有限,要完毕一个工作往往不是一屏内容中能搞定的。所以Android中有了Activity的概念,让用户能够把相关的子内容放到单独的Activity中,然后通过Intent在Activity间跳转。类似于浏览网页。点击链接跳转到还有一个网页。
这些同一交互过程中的一系列Activity成为一个Task。这些Activity执行在主线程ActivityThread中。Activity要展现出来的主视图是DecorView。它是一棵视图树。
ViewRootImpl负责管理这个视图树和与WMS交互。与WMS交互通过WindowManagerImpl和WindowManagerGlobal。DecorView被包括在系统的通用窗体抽象类Window其中。视图相应的图形缓冲区由Surface管理。其中涉及到的基本的类包括以下几个:
Activity:描写叙述一个Activity,它是与用户交互的基本单元。
ActivityThread:每个App进程有一个主线程,它由ActivityThread描写叙述。它负责这个App进程中各个Activity的调度和运行,以及响应AMS的操作请求等。
ApplicationThread:AMS和Activity通过它进行通信。对于AMS而言,ApplicationThread代表了App的主线程。简而言之,它是AMS与ActivityThread进行交互的接口。
注意ActivityThread和ApplicationThread之间的关系并不像Activity与Application。后者的关系是Application中包括了多个Activity。而前者ActivityThread和ApplicationThread是同一个东西的两种"View",ApplicationThread是在AMS眼中的ActivityThread。
ViewRootImpl:主要责任包含创建Surface,和WMS的交互和App端的UI布局和渲染。同一时候负责把一些事件发往Activity以便Activity能够截获事件。
每个加入到WMS中的窗体相应一个ViewRootImpl,通过WindowManagerGlobal向WMS加入窗体时创建。大多数情况下,它管理Activity顶层视图DecorView。总得来说,它相当于MVC模型中的Controller。
ViewRootImpl::W:用于向WMS提供接口,让WMS控制App端的窗体。它可看作是个代理,非常多时候会调用ViewRootImpl中的功能。这样的内嵌类的使用方法非常多,特别是这样的提供接口的代理类,如PhoneWindow::DecorView等。
Instrumentation:官方提供的Hook。主要用于測试。假设仅仅关注窗体管理流程的话能够先无视。
WindowManagerImpl:Activity中与窗体管理系统通信的代理类,实现类是WindowManagerGlobal。WindowManagerGlobal是App中全局的窗体管理模块,因此是个Singleton。
当中管理着该App中的ViewRootImpl,DecorView等结构,以有两个Activity的App为例:
Window:每一个App尽管都能够做得各不同样。可是作为有大量用户交互的系统,窗体之间必需要有统一的交互模式,这样才干减小用户的学习成本。
这些共性比方title,
action bar的显示和通用按键的处理等等。Window类就抽象了这些共性。另外。它定义了一组Callback,Activity通过实现这些Callback被调用来处理事件。注意要和在WMS中的窗体区分开来,WMS中的窗体更像是App端的View。
PhoneWindow:PhoneWindow是Window类的唯一实现,至少眼下是。这种设计下假设要加其他平台的Window类型更加方便。
每一个Activity会有一个PhoneWindow,在attach到ActivityThread时创建,保存在mWindow成员中。
Context:执行上下文。Activity和Service本质上都是一个Context。Context包括了它们作为执行实体的共性,如启动Activity,绑定Service,处理Broadcast和Receiver等等。注意Application也会有Context。Activity的Context是相应Activity的。Activity被杀掉(比方转屏后)后就变了。
所以要注意假设有生命周期非常长的对象有对Activity的Context的引用的话。转屏、返回这样的会引起Activity销毁的操作都会引起内存泄露。而Application的Context生命周期是和App进程一致的。关于Context的类结构图有以下的形式。Context是抽象类,定义了接口。ContextImpl是Context的实现类,包括了实现。而ContextWrapper是Context的包装类。它把请求delegate给当中的ContextImpl类去完毕。ContextThemeWrapper是ContextWrapper的装饰类,它在ContextWrapper的基础上提供了自己定义的主题。这结构初看有点乱,但结合以下的Decorator模式就一目了然了。
Surface:这是在App端管理图形缓冲区的类,当中最重要的是图形缓冲区队列。经由WMS从SF中得到IGraphicBufferProducer接口对象BufferQueue后。Surface便能够从该队列中queue和dequeue图形缓冲区。SurfaceControl在WMS中封装了Surface以及与SF的交互。Canvas和Surface从字面意思上非常像,但前者事实上更确切地说不是“画布”,而是“画家”。
Surface中的图形缓冲区才是App的画布。
上面这些基本类之间的主要关系例如以下:
当中比較重要的三个类的PhoneWindow,DecorView和ViewRootImpl。PhoneWindow和ViewRootImpl都包括了mDecor成员,它类型为DecorView。描写叙述了Activity的根视图。它也是ViewRootimpl和PhoneWindow间的枢纽。类似的。PhoneWindow父类中的Callback是PhoneWindow与Activity的枢纽,而ViewRootImpl::W是ViewRootImpl和WMS间的枢纽。DecorView依次继承自FrameLayout,ViewGroup和View,因此它本质上是一个View。仅仅是它是Activity最根部的View,它以下可能有非常多Subview。
DecorView描写叙述App窗体视图,而它的更新是由ViewRootImpl来控制的。
粗糙点说的话,假设用MVC模型来说的话,前者是View,后者是Controller。
ViewRootImpl中的内嵌类W就是给WMS通信的接口。
W的声明中有两个成员变量:mViewAncestor和mWindowSession。它一头连着App端的ViewRootImpl,一头连着WMS中的Session。且实现了IWindow的接口。
意味着它是App和WMS的桥梁。是WMS用来回调App端,让ViewRootImpl做事用的。举例来说。dispatchAppVisibility()的流程就是经过它来完毕的:WMS
->ViewRootImpl::W->ViewRootHandler->handleAppVisibility()->scheduleTraversals()。
Activity创建完后须要attach到主线程上。在attach()过程中会创建Window(实际是PhoneWindow),然后把PhoneWindow中的mCallback设为Activity。在PhoneWindow中两个关键内嵌类Callback和DecorView,Callback连接了Activity。DecorView连接了ViewRootImpl。这样,当ViewRootImpl有事件传来时,便能够沿着ViewRootImpl->DecorView->Window.Callback->Activity这条路来通知Activity。如按键事件就是通过这条路来传达的。
Android里还能够找到非常多这样的使用内嵌类来实现远端代理的样例,这样的设计使得系统满足最小隔离原则,Client端该用到哪些接口就暴露哪些接口。注意这样的类的函数都是跑在Binder线程中的,所以当中不能调用非线程安全的函数,也不能直接操作UI控件,所以一般都是往主线程消息队列里丢一个消息让其异步运行。
接下来,看下一个Activity的启动过程。以Launcher中启动一个App为例。比方在Launcher中我们点了一个图标启动一个App的Activity。Launcher里会运行:
Intent intent = new Intent("xxx");
startActivity(intent);
接下来的大体流程例如以下:
图比較大,抓大放小,看清里面的主要脉络就可以。App与AMS交互流程主要分下面几步:
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包装起来,这为策略的替换提供了便利,也使执行时更换策略成为可能。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamluemh1b2p1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
尽管眼下为止貌似仅仅有一种针对“Phone”的策略,所以还没看到这样设计的优点。可是,一方面,或许将来在多合一的移动设备上,笔记本,平板什么的能够切换,那么Policy自然也须要动态切换。
Android里还有非常多把这样的Policy单独拎出来的样例,如WindowManagerPolicy类。还有一方面,Android作为一个框架,须要让各个厂商把Android用到自己的平台上更加easy适配。将来假设作为眼镜,车载。智能家电等等嵌入式设备的统一平台。假设将Policy与其他模块紧耦合,那这些个平台上的代码就会差异越来越大。越来越难维护。
以下以类图的方式详细看下各模块之间的通信关系:
图中App和AMS的交互通过Binder。使用了代理模式。从App调用AMS是通过ActivityManagerProxy代理对象,它是本地对象ActivityManagerNative在App端的代理。实现了IActivityManager接口。提供了startActivity()这种AMS服务函数。而ActivityManagerNative的实现事实上就是AMS本身。
而从AMS调用App端用的是ApplicationThreadProxy代理对象。它实现了IApplicationThread接口,其相应的实现是ApplicationThreadNative本地对象。存在于App端,ApplicationThread是事实上现类。AMS能够通过它来向App发出如scheduleXXX这些个异步消息。
Activity在AMS中的相应物是ActivityRecord,在WMS中相应物为AppWindowToken。ActivityRecord::Token能够看作ActivityRecord的一个远端句柄。在WMS和App中分别存于AppWindowToken和ActivityClientRecord之中。ActivityThread中的mActivities存放了远程ActivityRecord::Token到本地ActivityClientRecord的映射,因为这个Token是全局唯一的。所以还能够用来作为HashMap的Key。ActivityRecord::Token实现了IApplicationToken。
当WMS要通知AMS窗体变化时,就是用的这个接口。
新启动的Activity的创建初始化主要是在handleLaunchActivity()中完毕的。handleLaunchActivity()的作用是载入指定的Activity并执行。这当中在App端主要是创建ActivityThread,Activity,PhoneWindow。DecorView等对象,并调用Activity生命周期中的onCreate()。onResume()函数执行用户逻辑。正常点的App里onCreate里会调用setContentView设置主视图。
setContentView()里主要是调用了installDecor()。当中会设置窗体的通用元素。如title,
action bar之类,还会把xml文件inflate成布局对象。
能够看到这时创建了DecorView。这便是Activity的主窗体的顶层视图。DecorView创建好后。handleResumeActivity()中会将它加入到WMS中去。当App向WMS加入窗体时。会调用WindowManagerImpl的addView()。注意WindowManagerImpl中的addView()函数和ViewGroup里的addView()函数全然不一样,后者是将View加入到本地的View
hierarchy中去,和WMS没有关系。addView()的流程例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamluemh1b2p1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
首先通过WindowManagerImpl的addView()会创建相应的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建立好后,接下来就是通过ViewRootImpl的setView将ViewRootImpl中的W注冊到WMS中,WMS会创建相应数据结构,并将其插入内部维护的窗体堆栈,还会与SF建立Session以备将来为之创建Surface。addView()运行完后这个Activity的主视图就正式对WMS可见了。总结来说。addView()的工作主要包含创建ViewRootImpl,和远程WMS建立Session,并将当前视图注冊到WMS这几步。
能够看到App端通过WindowManagerGlobal调用addView(),调用链到WMS就变成addWindow(),概念发生了改变,这也印证上面提到的App端和WMS端的Window概念不一样的说法。
从以上Activity启动的整个流程能够看到,窗体的加入和管理须要AMS和WMS两个Service的配合。
以下看看AMS与WMS的主要作用和结构。
AMS(ActivityManagerService)
Activity的管理者。
事实上除了Activity,AMS也管Service等组件信息。另外AMS还管理Process信息。以下是AMS几个重要数据结构:
ActivityRecord:描写叙述单个Activity。Activity堆栈中的基本单元。
ActivityRecord::Token:相应ActivityRecord的IBinder对象,能够看作远程对象的本地句柄。可用于LPC,又可用来作映射中的unique
ID。常常是两用的。
ProcessRecord:描写叙述一个App进程。包括了该进程中的Activity和Service列表。
TaskRecord:TaskRecord中的mActivities是ActivityRecord的列表,它们是依照历史顺序排序的。
ActivityStack:Activity堆栈,当中的ActivityRecord是通过TaskRecord这一层间接地被管理着。
ActivityStackSupervisor:ActivityStackSupervisor是ActivityStack的总管。
4.4中默认引入了两个ActivityStack。一个叫Home
stack。放Launcher和systemui,id为0;还有一个是Applicationstack,放App的Activity,id可能是随意值。定义例如以下:
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中须要看图片附件,然后会开imageview的Activity来显示它。依据不用的业务逻辑。我们会在启动Activity的Intent中设不同的FLAG(FLAG_ACTIVITY_NEW_TASK,FLAG_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。
总得来说。上面这些个数据结构之间的关系例如以下
WMS(WindowManagerService)
窗体的管理者。
与AMS不同,一些高层的App中的概念,如进程等,WMS是不care的。
由于WMS仅仅对窗体进行管理。哪个进程的它不关心。像Activity这些概念在WMS仍然有,由于Activity对窗体的管理会产生影响。
WMS主要责任是维护窗体堆栈。计算每一个窗体的layer信息交给SF,替App申请和调整画图Surface,当窗体显示状态变化了还要通知其他模块,另外还要处理系统输入。所以说,WMS可能是与其他模块交互最多的模块之中的一个了。它与AMS,App。SF及Input等模块都交集。说到窗体管理,首先看一下Android中有哪些窗体。Android中大体有下面几种窗体类型:1.应用窗体,一般来说就是Activity的主窗体。但也有些情况App没有Activity,直接把自己定义的View加入到WMS中。比方浮动窗体。2.子窗体,须要有一个父窗体,如Context
Menu,Option Menu,Popup Window和Dialog等。
3.系统窗体。如状态栏,锁屏窗体,输入法窗体,壁纸窗体和Toast之流。由系统创建的,不依赖于父窗体。
WMS中涉及到的主要数据结构有这么几个:
WindowState:WMS中最主要的元素,描写叙述WMS中的一个窗体。它既能够是由App加入过来的View,也能够是系统创建的系统窗体。
mAttrs为WindowManager.LayoutParams类型,描写叙述布局參数。mClient为IWindow类型,也就是App端的ViewRootImpl::W。
为了查找方便,WMS中的mWindowMap保存了IWindow到WindowState的映射,mTokenMap保存了IApplicationToken到WindowToken的映射。
Session:向App提供IWindowSession接口让其能够和WMS通信。每个App在WMS有一个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
SurfaceSession:WMS和SF之间的会话。
每一个App会在WMS中有一个相应的SurfaceSession,也会有一个相应的SurfaceComposerClient。
用于向SF申请和设置图形缓冲区等。
WindowToken: 描写叙述WM中一组相关的窗体。这些Window相应的WindowState放在其成员变量windows里。
其主要继承类AppWindowToken,它是针对App的WindowToken结构。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:每一个App的Activity相应一个AppWindowToken。当中的appToken为IApplicationToken类型,连接着相应的AMS中的ActivityRecord::Token对象,有了它就能够顺着AppWindowToken找到AMS中相应的ActivityRecord。当中allAppWindows是一个无序的列表。包括该Activity中全部的窗体。用dumpsys
window display能够查看z-ordered的AppWindowToken列表:
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是相应窗体的。所以AppWindowToken和WindowState是1:n的关系。举例来说。上面第一项AppWindowToken。它包括了PopupWindow子窗体,所以有相应两个WindowState。一般地说。一个Activity可能包括多个窗体。如启动窗体,PopupWindow等,这些窗体在WMS就会组织在一个AppWindowToken中。AppWindowToken及WindowState间的从属结构及WindowState间的父子结构能够通过下面成员表示。
Task:上面提到AppWindowToken保存了属于它的WindowState的有序列表,而它本身也作为一个列表被管理在TaskStack中的mTasks成员中,而且是按历史顺序存放的,最老的Task在最底下。
结合前面的AppWindowToken和WindowState之间的关系,能够了解到它们是以这样一个层级的关系组织起来的:
这个结构是不是非常眼熟。AMS里也有类似的结构。WMS里的TaskStack,相应前面AMS中的ActivityStack,这两者及其子结构会保持同步。从中我们能够发现。WMS和AMS中的数据结构是有相应关系的。如AMS中的TaskRecord和WMS中的Task,AMS中的ActivityRecord和WMS中的AppWindowToken。另外WMS中TaskStack的mTasks须要和AMS中ActivityStack的mTaskHistory顺序保持一致。
DisplayContent:表示一个显示设备上的内容,这个显示设备能够是外接显示屏,也能够是虚拟显示屏。当中mWindows是一个WindowState的有序(Z-ordered,底部最先)列表。
mStackBoxes包括了若干个StackBox,当中一个为HomeStack。还有一个是App的StackBox。全部的StackBox被组织成二叉树,StackBox是当中的节点。当中有三个重要成员变量,mFirst和mSecond指向左和右子结点(也是StackBox),StackBox的成员mStack才是我们真正关心的东西-TaskStack。能够看到,为了要把TaskStack存成树的结构。须要一个容器,这个容器就是StackBox。DisplayContent,StackBox和TaskStack的关系例如以下:
StackBox信息能够用am stack boxes或dumpsys
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
可见,在分屏情况下。这个结构以二叉树的形式分裂,形成这种结构:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamluemh1b2p1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
除了TaskStack。DisplayContent中的成员mTaskHistory也包括了一个有序的Task列表。
结合上面几个概念,能够得到以下的关系:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamluemh1b2p1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
逻辑上,一个Task(Task)能够包括多个Activity(相应AppWindowToken),每一个Activity能够包括多个窗体(相应WindowState),而每一个窗体都是可能被放在随意一个显示屏上的(想象一个Windows操作系统中外接显示器的情况)。因此就有了上面这个结构。从这个结构能够看出。WMS的主要任务之中的一个就是维护各窗体的Z-order信息。Z轴可看作是屏幕法向量方向上的坐标轴,值越大的层意味着离用户越近,会把值小的窗体给盖住。一方面。WMS须要知道各窗体的遮挡关系来做layout和分配释放Surface,还有一方面,这个Z-order信息会转化为窗体相应Surface的layer属性输出到SF,指导SF的渲染。
那么,这个列表是怎么管理的呢?我们知道,每一个窗体在WMS都有相应的WindowState,因此。本质上我们须要维护一个Z-order排序的WindowState列表。首先,TaskStack中包括了历史序的Task。每一个Task又包括了Z-ordered的AppWindowToken,AppWindowToken的成员windows又包括了一个Z-ordered的WindowState列表。前面提到过,一个AppWindowToken相应AMS中的一个ActivityRecord,因此这个列表包括了这个Activity中的全部窗体,子窗体,開始窗体等。还有一方面。DisplayContent中也有一个成员mWindows,指向一个Z-ordered的WindowState列表(列队越前面的在越底部),它描写叙述的是单个显示屏上的窗体集合。在加入窗体时会通过addAppWindowToListLocked()函数往这个窗体堆栈插入元素。
因为插入过程要考虑子窗体,開始窗体等的偏移量,往DisplayContent的mWindows插入元素时需考虑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是唯一的继承类。这样的结构看似可有可无,但假设以后厂商要加其他的策略,或更改已有策略,这样的设计就行提供良好的灵活性。
以上就是AMS和WMS的大体框架。粗糙地说,AMS管理Activity,Service和Process等信息。WMS管理应用和系统窗体。这两者既有联系又有非常大不同。Activity一般有窗体。Service能够有也能够没有窗体,而窗体不一定非要相应Activity或者Service。仅仅是非常多时候一个Activity中就一个顶层视图。相应WMS一个窗体,所以会给人一一相应的错觉,但这两者事实上没有直接关系。这就造就了AMS,WMS两大模块,尽管当中数据结构有非常多是保持同步的,可是设计上让它们分开,各司其职。异步工作。
从窗体管理的流程来说,App负责视图树的管理和业务逻辑。AMS管理和调度全部App中的组件,通知WMS组件的状态信息。
WMS帮App到SF申请和调整Surface,同一时候计算维护窗体的布局,z-order等信息,另外当显示状态发生变化时。WMS还要通知App作出调整。SF从WMS拿到各窗体相应Surface的属性和layer信息,同一时候从App拿到渲染好的图形缓冲区。进行进一步的合并渲染。放入framebuffer,最后用户就能在屏幕上看到App的窗体了。
版权声明:本文博主原创文章。博客,未经同意不得转载。
Android 4.4(KitKat)表格管理子系统 - 骨架的更多相关文章
- Android 4.4 KitKat 新特性
New in Android 4.4 KitKat 本文是一个概览,关于KitKat,也即Android4.4的新东西,先是功能型的,之后是设计上的. 很多特性本文并没有提到,很多提到的特性也只是简短 ...
- Android 4.4 KitKat, the browser and the Chrome WebView
Having V8 as the JavaScript engine for the new web view, the JavaScript performance if much better, ...
- 让你的短信应用迎接Android 4.4(KitKat)
原文地址:Getting Your SMS Apps Ready for KitKat 发送和接收短信是手机最基本的功能,很多的开发者也开发了很多成功的应用来增强Android这一方面的体验.你们当中 ...
- Using 1.7 requires compiling with Android 4.4 (KitKat); currently using API 10
今天编译一个project,我设置为api 14,可是编译报错: Using 1.7 requires compiling with Android 4.4 (KitKat); currently u ...
- Android 4.4(KitKat)中VSync信号的虚拟化
原文地址:http://blog.csdn.net/jinzhuojun/article/details/17293325 Android 4.1(Jelly Bean)引入了Vsync(Vertic ...
- Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程
本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. ...
- GetPathFromUri4kitkat【Android 4.4 kitkat以上及以下根据uri获取路径的方法】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 在Android4.4之前和之后,通过Intent调用文件管理器选择文件,获取的文件uri地址形式是不同的. Android6.0 ...
- Android 4.4 Kitkat Phone工作流程浅析(八)__Phone状态分析
本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象.与Google原生AOSP有些许差异.请读者知悉. ...
- 解决Using 1.7 requires compiling with Android 4.4 (KitKat); currently using API 4
有时候我们可能需要将项目的版本降低,比如4.4降低到2.2这样的,可能会遇到类似于这样的错误 Using 1.7 requires compiling with Android 4.4 (KitKat ...
随机推荐
- opencv环境的搭建,并打开一个本地PC摄像头。
1.opencv环境结构 推荐连结 http://www.cnblogs.com/Anykong/archive/2011/04/06/Anykong_OpenCV1.html 2.以下是基本測试,和 ...
- effective c++ 条款12 copy all parts of an object
这经常发生在更改代码的时候,当有自己的copy 赋值函数或者copy 构造函数时,编译器就不会维护这两个函数.导致发生遗忘. 可能出现的场景 class Customer { private: std ...
- ueditor问题解决
ueditor图片无法上传? 解决: imageUp.ashx 去掉这一行 <%@ Assembly Src="Uploader.cs" %> 参考: http://w ...
- 【Linux探索之旅】第二部分第三课:文件和目录,组织不会亏待你
内容简介 1.第二部分第三课:文件和目录,组织不会亏待你 2.第二部分第四课预告:文件操纵,鼓掌之中 文件和目录,组织不会亏待你 上一次课我们讲了命令行,这将成为伴随我们接下来整个Linux课程的一个 ...
- 2.大约QT数据库操作,简单的数据库连接操作,增删改查数据库,QSqlTableModel和QTableView,事务性操作,大约QItemDelegate 代理
Linux下的qt安装,命令时:sudoapt-get install qt-sdk 安装mysql数据库,安装方法參考博客:http://blog.csdn.net/tototuzuoquan ...
- [LeetCode235]Lowest Common Ancestor of a Binary Search Tree
题目: Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in th ...
- java提高篇(三)-----理解java的三大特性之多态
面向对象编程有三大特性:封装.继承.多态. 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据.对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法. 继承 ...
- 什么是PV,UV。
PV浏览(Page View).该网页访问量,每次页面打开PV统计+1,也刷新. IP接入号码指独立IP接入号码,计算基于独立IP在计算的时间段来计算访问我们的网站1二级IP接入号码. 是否这个计算在 ...
- Google API快速生成QR二维码
Google API快速生成QR二维码 现在来说生成二维码最简单的方法是使用Google Chart API来实现,再次膜拜Google大神- Google Chart API是一套可以让你在线生成报 ...
- 接近带给你AngularJS - 经验说明示例
接近带给你AngularJS列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自己定义指令 ------------ ...