WindowManagerService如何管理应用程序窗口

一、引言

如果对于Android窗口视图是怎么显示的还不是很清楚的话,可以看看我上一篇博文Android视图渲染过程分析,我们已经知道每一个Activity组件都有一个对应的ViewRoot对象、View对象以及WindowManager.LayoutParams对象。这三个对象的对应关系是由WindowManagerImpl类来维护的。具体来说,就是由WindowManagerImpl类的成员变量mRoots、mViews和mParams所描述的三个数组来维护的。例如,假设一个应用程序进程运行有两个Activity组件,那么WindowManagerImpl类的成员变量mRoots、mViews和mParams所描述的三个数组的大小就等于2,其中,mRoots[0]、mViews[0]和mParams[0]对应于第一个启动的Activity组件,而mRoots[1]、mViews[1]和mParams[1]对应于第二个启动的Activity组件。每一个ViewRoot对象都有一个类型为Surface的成员变量mSurface,它指向了一个Java层的Surface对象。这个Java层的Surface对象通过它的成员变量mNativeSurface与一个C++层的Surface对象。这个Surface类是用来在Android应用程序进程这一侧描述应用程序窗口的。在C++层中,每一个Surface对象都有一个对应的SurfaceControl对象。这个对应的SurfaceControl对象是用来设置应用程序窗口的属性,例如,设置大小、位置等属性 但是,与ViewRoot类的成员变量mSurface所对应的在C++层的Surface对象并没有一个对应的SurfaceControl对象,这是因为ViewRoot类并不需要设置应用程序窗口的属性,它需要做的只是往应用程序窗口的图形缓冲区填充UI数据,即它需要设置的只是应用程序窗口的纹理。应用程序窗口的纹理保存在Java层的Surface类的成员变量mCanvas所描述一个画布(Canvas)中,即通过这个画布可以访问到应用程序窗口的图形缓冲区。当ViewRoot类需要重新绘制与它对应的Activity组件的UI时,它就会调用它的成员函数draw来执行这个绘制的操作。ViewRoot类的成员函数draw首先通过获得保存它的成员变量mSurface内部的一块画布,然后再将这个画布传递给它的成员变量mView所描述的一个View对象的成员函数draw。View类的成员函数draw得到了这块画布之后,就可以随心所欲地上面绘制应用程序窗口的纹理了。这些纹理的绘制工作是通过Skia图形库API来进行的。

二、WindowManagerService管理窗口属性

那么,应用程序窗口的属性是由谁来管理的呢?这是由WindowManagerService服务来管理的,前面已经分析到了,在Android应用程序这一侧的Activity组件是由WindowManagerService服务来为它请求SurfaceFlinger服务创建一个Layer对象以及一个SurfaceLayer对象的。这个SurfaceLayer对象创建完成之后,WindowManagerService服务就会将它封装在一个Java层的Surface对象中,以后就可以通过这个Java层的Surface对象来请求SurfaceFlinger服务设置一个对应的应用程序窗口的属性。 由于Java层的Surface对象实现了Parcelable接口,因此,WindowManagerService服务在为一个Activity组件请求SurfaceFlinger服务创建一个Layer对象以及一个SurfaceLayer对象之后,就可以将得到的Java层的Surface对象跨进程地返回给该Activity组件。Activity组件得到这个Surface对象之后,再使用保存在里面的SurfaceLayer对象来初始化与它所对应的一个ViewRoot对象的成员变量mSurface所描述的一个Java层的Surface对象。
那么,WindowManagerService服务又是什么时候会为一个Activity组件请求SurfaceFlinger服务创建一个Layer对象以及一个SurfaceLayer对象呢?ViewRoot类有一个类型为IWindowSession的静态成员变量sWindowSession,它指向的实际上是一个实现了IWindowSession接口的Binder对象。这个Binder对象的类型为Session,运行在WindowManagerService服务这一侧。当一个Activity组件的UI第一次要被绘制之前,它所运行在的应用程序进程就会通过ViewRoot类的静态成员变量sWindowSession来向WindowManagerService服务发送一个请求。WindowManagerService服务接收到这个请求之后,再请求SurfaceFlinger服务为这个Activity组件创建一个Layer对象以及一个SurfaceLayer对象。这样,这个Activity组件的UI才能真正地绘制在屏幕中。 至此,我们就简要分析完成了在Android应用程序这一侧的Activity组件与UI相关的类的实现,接下来我们继续分析在WindowManagerService服务这一侧的WindowState类的实现。
先来看看WindowState的类图分析:
这里写图片描述
在Android应用程序这一侧,每一个Activity组件在WindowManagerService服务这一侧都有一个对应的WindowState对象,用来描述Activity组件的窗口状态。从上面类图中我们可以看出WindowState类有两个重要的成员变量mSession和mSurface,它们的类型分别为SurfaceSession和Surface。接下来,我们就来分析这两个成员变量的作用。

  • mSession成员变量

前面有分析到,Activity组件是在启动完成之后,请求WindowManagerService服务为它创建一个WindowState对象的。创建完成这个WindowState对象之后,WindowManagerService服务再调用它的成员函数attach来为它附加一个SurfaceSession对象。WindowState类的成员函数attach又是通过调用它的成员变量mSession所描述的一个Session对象的成员函数windowAddedLocked来附加一个SurfaceSession对象的。 Session类有一个类型为SurfaceSession的成员变量mSurfaceSession。当WindowState类的成员函数attach调用Session类的成员函数windowAddedLocked来为一个WindowState对象附加一个SurfaceSession对象的时候,后者首先会检查它的成员变量mSurfaceSession是否已经指向了一个SurfaceSession对象。如果如果指向了的话,那么Session类的成员函数windowAddedLocked就什么也不用做,否则的话,Session类的成员函数windowAddedLocked就会创建一个SurfaceSession对象,并且保存在它的成员变量mSurfaceSession中。 SurfaceSession类有一个类型为int的成员变量mClient,它保存的是一个C++层的SurfaceComposerClient对象的地址,即每一个Java层的SurfaceSession对象在C++层都有一个对应的SurfaceComposerClient对象。当一个SurfaceSession对象创建的时候,与它所关联的SurfaceComposerClient对象也会同时被创建。而SurfaceComposerClient类用来描述Android应用程序进程与SurfaceFlinger服务之间的一个连接,即每一个与UI相关的Android应用程序进程都有一个SurfaceComposerClient对象。既然SurfaceComposerClient是用来描述Android应用程序进程与SurfaceFlinger服务的连接的,那么为什么WindowManagerService服务会在内部创建SurfaceComposerClient对象呢?由于WindowManagerService需要请求SurfaceFlinger服务来设置Android应用程序窗口的属性,例如,设置应用程序窗口的位置、大小等,因此,它就需要为每一个Android应用程序进程创建一个SurfaceComposerClient对象连接到SurfaceFlinger服务中去,以便可以和SurfaceFlinger服务进行通信。
总结:
在WindowManagerService服务中,每一个Android应用程序进程都对应有一个SurfaceComposerClient对象。由于每一个SurfaceComposerClient对象都关联有一个SurfaceSession对象,因此,我们又可以推断出每一个Android应用程序进程在WindowManagerService服务中都对应有一个SurfaceSession对象。由于每一个SurfaceSession对象所属的Session对象是一个Binder本地对象,并且它的Binder代理对象是保存在Android应用程序进程这一侧的ViewRoot类的静态成员变量sWindowSession中,因此,我们又可以推断出每一个Android应用程序进程在WindowManagerService服务都有一个对应的Session对象。综合起来就是,每一个Android应用程序进程在WindowManagerService服务这一侧对应有一个Session对象、一个SurfaceSession对象以及一个SurfaceComposerClient对象。由于每一个Android应用程序进程都可以运行若干个Activity组件,因此,我们又可以说,Activity组件与WindowServiceManager服务这一侧的Session对象、SurfaceSession对象以及SurfaceComposerClient对象是多对一的关系。

  • mSurface成员变量

    上面已经分析完mSession成员变量的作用,接下来我们将要分析mSurface的作用。mSurface它的类型为Surface,前面我们已经介绍过Surface类在Android应用程序进程这一侧的作用了,接下来我们就介绍它在WindowManagerService这一侧的作用。WindowManagerService服务会在内部为每一个应用程序窗口,即每一个Activity组件,创建一个SurfaceLayer对象,这个SurfaceLayer对象是封装成一个Java层的Surface对象中的。在Java层的Surface类中,有一个类型为int的成员变量mSurfaceControl,它保存的是在C++层的一个SurfaceControl对象的地址值,即在WindowManagerService服务这一侧,每一个Java层的Surface对象在 C++层都有一个对应的SurfaceControl对象。这里强调是在WindowManagerService服务这一侧,是因为在前面提到,在Android应用程序这一侧,每一个Activity组件所对应的Java层的Surface对象在C++层是没有一个对应的SurfaceControl对象,而只是对应有一个C++层的Surface对象。通过C++层的SurfaceControl对象可以设置应用程序窗口的属性,而通过C++层的Surface对象则可以设置应用程序窗口的图形缓冲区,即设置应用程序窗口的纹理,因此,我们就可以知道应用程序窗口的属性是由WindowManagerService服务来设置的,而应用程序窗口的纹理是由它所在的进程负责设置的。 那么,应用程序窗口的视图对象及其所关联的ViewRoot对象是什么时候开始创建的呢?Activity组件在启动的时候,系统会为它创建窗口对象(Window),同时,系统也会为这个窗口对象创建视图对象。另一方面,当Activity组件被激活的时候,系统如果发现与它的应用程序窗口视图对象所关联的ViewRoot对象还没有创建,那么就会先创建这个ViewRoot对象,以便接下来可以将它的UI渲染出来。

    三、应用程序窗口的视图对象及其所关联的ViewRoot对象的创建过程

    这个过程太繁琐复杂了,我也只是读懂一些皮毛,大家一起互相学习。借助之前老罗,罗老师画过的一张图来分析它的创建过程:
    这里写图片描述
    现在我们对这个创建过程进行分析:
    从上图我们看出方法首先调用ActivityThread类的成员方法performLaunchActivity来创建要启动的Activity组件。在创建Activity组件的过程中,还会为该Activity组件创建窗口对象和视图对象。Activity组件创建完成之后,就可以将它激活起来了,这是通过调用ActivityThread类的成员函数handleResumeActivity来执行的。ActivityThread类的成员方法performLaunchActivity的实现主要是实现应用程序窗口视图对象的创建过程,ActivityThread类的成员方法handleResumeActivity的实现是应用程序窗口视图对象所关联的ViewRoot对象的创建过程。接下来我们来看看这两个方法具体的实现过程:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    unscheduleGcIdler();
    mSomeActivitiesChanged = true;

    if (r.profilerInfo != null) {
        mProfiler.setProfiler(r.profilerInfo);
        mProfiler.startProfiling();
    }
    // Make sure we are running with the most recent config.
    handleConfigurationChanged(null, null);

    WindowManagerGlobal.initialize();

    Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed);

        if (!r.activity.mFinished && r.startsNotResumed) {
            try {
                r.activity.mCalled = false;
                mInstrumentation.callActivityOnPause(r.activity);
                if (r.isPreHoneycomb()) {
                    r.state = oldState;
                }
                if (!r.activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onPause()");
                }

            } catch (SuperNotCalledException e) {
                throw e;

            } catch (Exception e) {
                if (!mInstrumentation.onException(r.activity, e)) {
                    throw new RuntimeException(
                            "Unable to pause activity "
                            + r.intent.getComponent().toShortString()
                            + ": " + e.toString(), e);
                }
            }
            r.paused = true;
        }
    } else {
        // If there was an error, for any reason, tell the activity
        // manager to stop us.
        try {
            ActivityManagerNative.getDefault()
                .finishActivity(r.token, Activity.RESULT_CANCELED, null, false);
        } catch (RemoteException ex) {
            // Ignore
        }
    }
}

从上面可以看出handleResumeActivity方法里有回调performLaunchActivity方法,ActivityThread类的成员函数handleResumeActivity首先调用另外一个成员函数performResumeActivity来通知Activity组件,它要被激活了,即会导致Activity组件的成员函数onResume被调用。ActivityThread类的成员函数performResumeActivity的返回值是一个ActivityClientRecord对象r,这个ActivityClientRecord对象的成员变量activity描述的就是正在激活的Activity组件a, ActivityThread类的成员函数handleResumeActivity接下来判断正在激活的Activity组件接下来是否是可见的。如果是可见的,那么变量willBeVisible的值就会等于true。Activity类的成员变量mStartedActivity用来描述一个Activity组件是否正在启动一个新的Activity组件,并且等待这个新的Activity组件的执行结果。如果是的话,那么这个Activity组件的成员变量mStartedActivity的值就会等于true,表示在新的Activity组件的执行结果返回来之前,当前Activity组件要保持不可见的状态。因此,当Activity组件a的成员变量mStartedActivity的值等于true的时候,它接下来就是不可见的,否则的话,就是可见的。虽然说在Activity组件a的成员变量mStartedActivity的值等于true的情况下,它接下来的状态要保持不可见的,但是有可能它所启动的Activity组件的UI不是全屏的。在这种情况下,Activity组件a的UI仍然是有部分可见的,这时候也要将变量willBeVisible的值设置为true。因此,如果前面得到变量willBeVisible的值等于false,那么ActivityThread类的成员函数handleResumeActivity接下来就会通过Binder进程间通信机制来调用ActivityManagerService服务的成员函数willActivityBeVisible来检查位于Activity组件a上面的其它Activity组件(包含了Activity组件a正在等待其执行结果的Activity组件)是否是全屏的。如果不是,那么ActivityManagerService服务的成员函数willActivityBeVisible的返回值就会等于true,表示接下来需要显示Activity组件a。 前面得到的ActivityClientRecord对象r的成员变量window用来描述当前正在激活的Activity组件a所关联的应用程序窗口对象。当它的值等于null的时候,就表示当前正在激活的Activity组件a所关联的应用程序窗口对象还没有关联一个ViewRoot对象。进一步地,如果这个正在激活的Activity组件a还活着,并且接下来是可见的,即ActivityClientRecord对象r的成员变量mFinished的值等于false,并且前面得到的变量willBeVisible的值等于true,那么这时候就说明需要为与Activity组件a所关联的一个应用程序窗口视图对象关联的一个ViewRoot对象。 将一个Activity组件的应用程序窗口视图对象与一个ViewRoot对象关联是通过该Activity组件所使用的窗口管理器来执行的。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   ActivityThread.performLaunchActivity(" + r + ")");
    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }

    ComponentName component = r.intent.getComponent();
    if (component == null) {
        component = r.intent.resolveActivity(
            mInitialApplication.getPackageManager());
        r.intent.setComponent(component);
    }

    if (r.activityInfo.targetActivity != null) {
        component = new ComponentName(r.activityInfo.packageName,
                r.activityInfo.targetActivity);
    }

    Activity activity = null;
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        if (r.state != null) {
            r.state.setClassLoader(cl);
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to instantiate activity " + component
                + ": " + e.toString(), e);
        }
    }

    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        if (activity != null) {
            Context appContext = createBaseContextForActivity(r, activity);
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
            Configuration config = new Configuration(mCompatConfiguration);
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                    + r.activityInfo.name + " with config " + config);
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor);

            if (customIntent != null) {
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            activity.mStartedActivity = false;
            int theme = r.activityInfo.getThemeResource();
            if (theme != 0) {
                activity.setTheme(theme);
            }

            activity.mCalled = false;
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
            if (!activity.mCalled) {
                throw new SuperNotCalledException(
                    "Activity " + r.intent.getComponent().toShortString() +
                    " did not call through to super.onCreate()");
            }
            r.activity = activity;
            r.stopped = true;
            if (!r.activity.mFinished) {
                activity.performStart();
                r.stopped = false;
            }
            if (!r.activity.mFinished) {
                if (r.isPersistable()) {
                    if (r.state != null || r.persistentState != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                r.persistentState);
                    }
                } else if (r.state != null) {
                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                }
            }
            if (!r.activity.mFinished) {
                activity.mCalled = false;
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state,
                            r.persistentState);
                } else {
                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
                }
                if (!activity.mCalled) {
                    throw new SuperNotCalledException(
                        "Activity " + r.intent.getComponent().toShortString() +
                        " did not call through to super.onPostCreate()");
                }
            }
        }
        r.paused = true;

        mActivities.put(r.token, r);

    } catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
        if (!mInstrumentation.onException(activity, e)) {
            throw new RuntimeException(
                "Unable to start activity " + component
                + ": " + e.toString(), e);
        }
    }

    return activity;
}

它主要就是创建一个Activity组件实例,并且调用这个Activity组件实例的成员函数onCreate来让其执行一些自定义的初始化工作。 Activity类的成员函数setContentView首先调用另外一个成员函数getWindow来获得成员变量mWindow所描述的一个窗口对象,接着再调用这个窗口对象的成员函数setContentView来执行创建应用程序窗口视图对象的工作。

总结:
一个Activity组件所使用的本地窗口管理器保存它的成员变量mWindowManager中,这可以通过Activity类的成员函数getWindowManager来获得,再来看看Activity类的成员函数getWindowManager的实现。


    /** Retrieve the window manager for showing custom windows. */
    public WindowManager getWindowManager() {
        return mWindowManager;
    }

由于要给Activity组件a的应用程序窗口视图对象关联一个ViewRoot对象,因此,我们就需要首先获得这个应用程序窗口视图对象。从前面的Step 6可以知道,一个Activity组件的应用程序窗口视图对象保存在与其所关联的一个应用程序窗口对象的内部,因此,我们又要首先获得这个应用程序窗口对象。与一个Activity组件所关联的应用程序窗口对象可以通过调用该Activity组件的成员函数getWindow来获得。一旦获得了这个应用程序窗口对象(类型为PhoneWindow)之后,我们就可以调用它的成员函数getDecorView来获得它内部的视图对象。在接下来的Step 8和Step 9中,我们再分别分析Activity类的成员函数Activity类的成员函数getWindow和PhoneWindow类的成员函数getDecorView的实现。在关联应用程序窗口视图对象和ViewRoot对象的时候,还需要第三个参数,即应用程序窗口的布局参数,这是一个类型为WindowManager.LayoutParams的对象,可以通过调用应用程序窗口的成员函数getAttributes来获得。一切准备就绪之后,还要判断最后一个条件是否成立,即当前正在激活的Activity组件a在本地进程中是否是可见的,即它的成员变量mVisibleFromClient的值是否等于true。如果是可见的,那么最后就可以调用前面所获得的一个本地窗口管理器wm(类型为LocalWindowManager)的成员函数addView来执行关联应用程序窗口视图对象和ViewRoot对象的操作。
至此,WindowManagerService管理应用程序窗口的分析就结束了,对于太底层原理的东西我也是刚刚接触,掌握的只是一些最基础,最皮毛的东西,我会继续努力,不断改进更新。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值