首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > Android >

Android应用程序窗口(Activity)与WindowManagerService服务的联接过程分析

2012-12-27 
Android应用程序窗口(Activity)与WindowManagerService服务的连接过程分析在前两文中,我们分析了Activity

Android应用程序窗口(Activity)与WindowManagerService服务的连接过程分析

        在前两文中,我们分析了Activity组件的窗口对象和视图对象的创建过程。Activity组件在其窗口对象和视图对象创建完成之后,就会请求与WindowManagerService建立一个连接,即请求WindowManagerService为其增加一个WindowState对象,用来描述它的窗口状态。在本文中,我们就详细分析Activity组件与WindowManagerService的连接过程。

        我们从两方面来看Activity组件与WindowManagerService服务之间的连接。一方面是从Activity组件到WindowManagerService服务的连接,另一方面是从WindowManagerService服务到Activity组件的连接。从Activity组件到WindowManagerService服务的连接是以Activity组件所在的应用程序进程为单位来进行的。当一个应用程序进程在启动第一个Activity组件的时候,它便会打开一个到WindowManagerService服务的连接,这个连接以应用程序进程从WindowManagerService服务处获得一个实现了IWindowSession接口的Session代理对象来标志。从WindowManagerService服务到Activity组件的连接是以Activity组件为单位来进行的。在应用程序进程这一侧,每一个Activity组件都关联一个实现了IWindow接口的W对象,这个W对象在Activity组件的视图对象创建完成之后,就会通过前面所获得一个Session代理对象来传递给WindowManagerService服务,而WindowManagerService服务接收到这个W对象之后,就会在内部创建一个WindowState对象来描述与该W对象所关联的Activity组件的窗口状态,并且以后就通过这个W对象来控制对应的Activity组件的窗口状态。

         上述Activity组件与WindowManagerService服务之间的连接模型如图1所示:

Android应用程序窗口(Activity)与WindowManagerService服务的联接过程分析

图1 Activity组件与WindowManagerService服务之间的连接模型

        从图1还可以看出,每一个Activity组件在ActivityManagerService服务内部,都对应有一个ActivityRecord对象,这个ActivityRecord对象是Activity组件启动的过程中创建的,用来描述Activity组件的运行状态,这一点可以参考前面Android应用程序启动过程源代码分析一文。这样,每一个Activity组件在应用程序进程、WindowManagerService服务和ActivityManagerService服务三者之间就分别一一地建立了连接。在本文中,我们主要关注Activity组件在应用程序进程和WindowManagerService服务之间以及在WindowManagerService服务和ActivityManagerService服务之间的连接。

        接下来我们就通过Session类、W类和WindowState类的实现来简要描述Activity组件与WindowManagerService服务之间的连接,如图2和图3所示:

Android应用程序窗口(Activity)与WindowManagerService服务的联接过程分析

图2 W类的实现

Android应用程序窗口(Activity)与WindowManagerService服务的联接过程分析

图3 Session类和WindowState类的实现

        W类实现了IWindow接口,它的类实例是一个Binder本地对象。从前面Android应用程序窗口(Activity)的视图对象(View)的创建过程分析一文可以知道,一个Activity组件在启动的过程中,会创建一个关联的ViewRoot对象,用来配合WindowManagerService服务来管理该Activity组件的窗口状态。在这个ViewRoot对象内部,有一个类型为W的成员变量mWindow,它是在ViewRoot对象的创建过程中创建的。

        ViewRoot类有一个静态成员变量sWindowSession,它指向了一个实现了IWindowSession接口的Session代理对象。当应用程序进程启动第一个Activity组件的时候,它就会请求WindowManagerService服务发送一个建立连接的Binder进程间通信请求。WindowManagerService服务接收到这个请求之后,就会在内部创建一个类型为Session的Binder本地对象,并且将这个Binder本地对象返回给应用程序进程,后者于是就会得到一个Session代理对象,并且保存在ViewRoot类的静态成员变量sWindowSession中。

        有了这个Session代理对象之后,应用程序进程就可以在启动Activity组件的时候,调用它的成员函数add来将与该Activity组件所关联的一个W对象传递给WindowManagerService服务,后者于是就会得到一个W代理对象,并且会以这个W代理对象来创建一个WindowState对象,即将这个W代理对象保存在新创建的WindowState对象的成员变量mClient中。这个WindowState对象的其余成员变量的描述可以参考前面Android应用程序窗口(Activity)实现框架简要介绍和学习计划一文的图7,这里不再详述。

        Session类的描述同样可以参考前面Android应用程序窗口(Activity)实现框架简要介绍和学习计划一文,这里我们主要描述一下它的作用。从图3可以看出,Session类实现了IWindowSession接口,因此,应用程序进程就可以通过保存在ViewRoot类的静态成员变量sWindowSession所描述的一个Session代理对象所实现的IWindowSession接口来与WindowManagerService服务通信,例如:

        1. 在Activity组件的启动过程中,调用这个IWindowSession接口的成员函数add可以将一个关联的W对象传递到WindowManagerService服务,以便WindowManagerService服务可以为该Activity组件创建一个WindowState对象。

        2. 在Activity组件的销毁过程中,调用这个这个IWindowSession接口的成员函数remove来请求WindowManagerService服务之前为该Activity组件所创建的一个WindowState对象,这一点可以参考前面Android应用程序键盘(Keyboard)消息处理机制分析一文的键盘消息接收通道注销过程分析。

        3. 在Activity组件的运行过程中,调用这个这个IWindowSession接口的成员函数relayout来请求WindowManagerService服务来对该Activity组件的UI进行布局,以便该Activity组件的UI可以正确地显示在屏幕中。

        我们再来看W类的作用。从图2可以看出,W类实现了IWindow接口,因此,WindowManagerService服务就可以通过它在内部所创建的WindowState对象的成员变量mClient来要求运行在应用程序进程这一侧的Activity组件来配合管理窗口的状态,例如:

        1. 当一个Activity组件的窗口的大小发生改变后,WindowManagerService服务就会调用这个IWindow接口的成员函数resized来通知该Activity组件,它的大小发生改变了。

        2. 当一个Activity组件的窗口的可见性之后,WindowManagerService服务就会调用这个IWindow接口的成员函数dispatchAppVisibility来通知该Activity组件,它的可见性发生改变了。

        3. 当一个Activity组件的窗口获得或者失去焦点之后,WindowManagerService服务就会调用这个IWindow接口的成员函数windowFoucusChanged来通知该Activity组件,它的焦点发生改变了。

        理解了Activity组件在应用程序进程和WindowManagerService服务之间的连接模型之后,接下来我们再通过简要分析Activity组件在WindowManagerService服务和ActivityManagerService服务之间的连接。

        Activity组件在WindowManagerService服务和ActivityManagerService服务之间的连接是通过一个AppWindowToken对象来描述的。AppWindowToken类的实现如图4所示:

Android应用程序窗口(Activity)与WindowManagerService服务的联接过程分析

图4 AppWindowToken类的实现

        每一个Activity组件在启动的时候,ActivityManagerService服务都会内部为该Activity组件创建一个ActivityRecord对象,并且会以这个ActivityRecord对象所实现的一个IApplicationToken接口为参数,请求WindowManagerService服务为该Activity组件创建一个AppWindowToken对象,即将这个IApplicationToken接口保存在新创建的AppWindowToken对象的成员变量appToken中。同时,这个ActivityRecord对象还会传递给它所描述的Activity组件所运行在应用程序进程,于是,应用程序进程就可以在启动完成该Activity组件之后,将这个ActivityRecord对象以及一个对应的W对象传递给WindowManagerService服务,后者接着就会做两件事情:

       1. 根据获得的ActivityRecord对象的IApplicationToken接口来找到与之对应的一个AppWindowToken对象;

       2. 根据获得的AppWindowToken对象以及前面传递过来的W代理对象来为正在启动的Activity组件创建一个WindowState对象,并且将该AppWindowToken对象保存在新创建的WindowState对象的成员变量mAppToken中。

       顺便提一下,AppWindowToken类是从WindowToken类继续下来的。WindowToken类也是用来标志一个窗口的,不过这个窗口类型除了是应用程序窗口,即Activity组件窗口之外,还可以是其它的,例如,输入法窗口或者壁纸窗口类型等,而AppWindowToken类只是用来描述Activity组件窗口。当WindowToken类是用来描述Activity组件窗口的时候,它的成员变量token指向的就是用来描述该Activity组件的一个ActivityRecord对象所实现的一个IBinder接口,而成员变量appWindowToken指向的就是其子类AppWindowToken对象。当另一方面,当WindowToken类是用来描述非Activity组件窗口的时候,它的成员变量appWindowToken的值就会等于null。这样,我们就可以通过WindowToken类的成员变量appWindowToken的值来判断一个WindowToken对象是否是用来描述一个Activity组件窗口的,即是否是用来描述一个应用程序窗口的。

       上面所描述的Activity组件在ActivityManagerService服务和WindowManagerService服务之间以及应用程序进程和WindowManagerService服务之间的连接模型比较抽象,接下来,我们再通过三个过程来分析它们彼此之间的连接模型,如下所示:

       1. ActivityManagerService服务请求WindowManagerService服务为一个Activity组件创建一个AppWindowToken对象的过程;

       2. 应用程序进程请求WindowManagerService服务创建一个Session对象的过程;

       3. 应用程序进程请求WindowManagerService服务为一个Activity组件创建一个WindowState对象的过程。

       通过这三个过程的分析,我们就可以对应用程序进程、ActivityManagerService服务和WindowManagerService服务的关系有一个深刻的认识了。

       一. AppWindowToken对象的创建过程

      从前面Android应用程序启动过程源代码分析一文的Step 9可以知道,Activity组件在启动的过程中,会调用到ActivityStack类的成员函数startActivityLocked,该函数会请求WindowManagerService服务为当前正在启动的Activity组件创建一个AppWindowToken对象。接下来,我们就从ActivityStack类的成员函数startActivityLocked开始分析一个AppWindowToken对象的创建过程,如图5所示:

Android应用程序窗口(Activity)与WindowManagerService服务的联接过程分析

图4 AppWindowToken对象的创建过程

        这个过程可以分为3步,接下来我们就详细分析每一个步骤。

        Step 1. ActivityStack.startActivityLocked


图5 Session对象的创建过程

        这个过程可以分为5个步骤,接下来我们就详细分析每一个步骤。

        Step 1. WindowManagerImpl.addView


图6 WindowState对象的创建过程

        这个过程可以分为7个步骤,接下来我们就详细分析每一个步骤。

        Step 1. ViewRoot.setView

void nativeClassInit(JNIEnv* env, jclass clazz){    ......    jclass surfaceSession = env->FindClass("android/view/SurfaceSession");    sso.client = env->GetFieldID(surfaceSession, "mClient", "I");    ......}
       回到函数SurfaceSession_init中,它首先创建一个SurfaceComposerClient对象client,接着再增加这个SurfaceComposerClient对象的强引用计数,因为再接下来会将这个SurfaceComposerClient对象的地址值保存在参数clazz所描述的一个SurfaceSession对象的成员变量mClient中,这相当于是参数clazz所描述的一个SurfaceSession对象引用了刚才所创建的SurfaceComposerClient对象client。

       在前面Android应用程序与SurfaceFlinger服务的关系概述和学习计划这一系列的文章中,我们已经分析过SurfaceComposerClient类的作用了,这主要就是用来在应用程序进程和SurfaceFlinger服务之间建立连接的,以便应用程序进程可以为运行在它里面的应用程序窗口请求SurfaceComposerClient创建绘制表面(Surface)的操作等。

       这样,每一个Java层的SurfaceSession对象在C++层就都有一个对应的SurfaceComposerClient对象,因此,Java层的应用程序就可以通过SurfaceSession类来和SurfaceFlinger服务建立连接。

       至此,我们就分析完成一个WindowState对象的创建过程了,通过这个过程我们就可以知道,每一个Activity组件窗口在WindowManagerService服务内部都有一个对应的WindowState对象,用来描述它的窗口状态。

       至此,我们也分析完成Android应用程序窗口与WindowManagerService服务的连接过程了。从这个连接过程以及前面Android应用程序窗口(Activity)的窗口对象(Window)的创建过程分析和Android应用程序窗口(Activity)的视图对象(View)的创建过程分析这两篇文章,我们就可以知道,为了实现一个Activity组件的UI,无论是应用程序进程,还是WindowManagerService,都做了大量的工作,例如,应用程序进程为它创建一个窗口(Window)对象、一个视图(View)对象、一个ViewRoot对象、一个W对象,WindowManagerService服务为它创建一个AppWindowToken对象和一个WindowState对象。此外,WindowManagerService服务还为一个Activity组件所运行在的应用程序进程创建了一个Session对象。理解这些对象的实现以及作用对我们了解Android应用程序窗口的实现框架以及WindowManagerService服务的实现原理都是非常重要的。

       虽然到目前为止,我们已经为Android应用程序窗口创建了很多对象,但是我们仍然还有一个最重要的对象还没有创建,那就是Android应用程序窗口的绘图表面,即用来渲染UI的Surface还没有创建。从前面Android应用程序与SurfaceFlinger服务的关系概述和学习计划这一系列的文章可以知道,这个Surface是要请求SurfaceFlinger服务来创建的,因此,在接下来的一篇文章中,我们就将继续分析Android应用程序窗口的绘图表面(Surface)的创建过程,敬请关注!

4楼qinjuning4天前 14:41
这篇文章很详细,讲解了ViewRoot到WMS的链接以及数据创建过程。但我有个问题,希望老罗能回答下。步骤位于: 二. Session对象的创建过程 。 n public static IWindowSession getWindowSession(Looper mainLooper) {n synchronized (mStaticInit) {n if (!mInitialized) {n try {n InputMethodManager imm = InputMethodManager.getInstance(mainLooper);n sWindowSession = IWindowManager.Stub.asInterface(n ServiceManager.getService("window"))n .openSession(imm.getClient(), imm.getInputContext());n mInitialized = true;n } catch (RemoteException e) {n }n }n return sWindowSession;n }n }n这个获取sWindowSession的过程,是每个应用程序对应一个sWindowSession? 还是就只有一个sWindowSession 。 应为这个getWindowSession的变量都是static的 。或者是你提到的线程私有数据吗 ? 刚刚又看了些,ViewRoot继承与Handler,莫非是Handler类保证了这个线程私有数据吗 ?不太明白, 希望老罗能解答下。
Re: Luoshengyang4天前 15:06
回复qinjuningn每个应用程序进程都有一个,不是线程私有,也不是整个系统只有一个。
Re: qinjuning4天前 15:09
结论我倒明白,但不知是怎么做到的,囧。原因如下:n static boolean mInitialized = false; //是个静态变量 。n 第一次初始化后,mInitialized 就为true了。以后的应用程序获得的sWindowSession(也是static)就都是一个对象了额,也就不会继续创建sWindowSession了。 照代码来看,是这么理解的,不知老罗有什么看法没?
Re: Luoshengyang3天前 14:56
回复qinjuningn结论你都明白了,代码你也理解得没问题,我没有什么看法。
Re: qinjuning3天前 21:23
回复Luoshengyangn只能继续纠结了。。 不过这个变量mInitialized 竟然是以m开头, 很诡异。 元芳有木有啊。老罗~~
Re: Luoshengyang3天前 22:21
回复qinjuningn连变量的命名方式你都这么在乎,看来你是想不纠结都不行了。
3楼dr87370104天前 14:27
杀花,又在零点更新啊辛苦了
2楼a876367644天前 13:27
mViewVisibility:这是一个布尔变量,使用参数viewVisibility来初始化,表示当前所创建的WindowState对象所描述的窗口视图的可见性-----作用是布尔变量的作用,但定义是int。。
Re: Luoshengyang4天前 13:53
回复a87636764n看漏了眼,已改。
1楼a876367645天前 09:14
真心不知道 那些点 “踩”的人是什么心态。。。。

热点排行