WindowManagerService服务会为应用程序窗口创建一个到SurfaceFlinger服务的连接。有了这个连接之后,WindowManagerService服务就可以为应用程序窗口创建绘图表面了,以便可以用来渲染窗口的UI。
每一个在C++层实现的应用程序窗口都需要有一个绘图表面,然后才可以将自己的UI表现出来。这个绘图表面是需要由应用程序进程请求SurfaceFlinger服务来创建的,在SurfaceFlinger服务内部使用一个Layer对象来描述,同时,SurfaceFlinger服务会返回一个实现了ISurface接口的Binder本地对象给应用程序进程,于是,应用程序进程就可以获得一个实现了ISurface接口的Binder代理对象。有了这个实现了ISurface接口的Binder代理对象之后,在C++层实现的应用程序窗口就可以请求SurfaceFlinger服务分配图形缓冲区以及渲染已经填充好UI数据的图形缓冲区了。
对于在Java层实现的Android应用程序窗口来说,它也需要请求SurfaceFlinger服务为它创建绘图表面,这个绘图表面使用一个Surface对象来描述。由于在Java层实现的Android应用程序窗口还要接受WindowManagerService服务管理,因此,它的绘图表面的创建流程就会比在C++层实现的应用程序窗口复杂一些。具体来说,就是在在Java层实现的Android应用程序窗口的绘图表面是通过两个Surface对象来描述,一个是在应用程序进程这一侧创建的,另一个是在WindowManagerService服务这一侧创建的,它们对应于SurfaceFlinger服务这一侧的同一个Layer对象,如图所示:
在应用程序进程这一侧,每一个应用程序窗口,即每一个Activity组件,都有一个关联的Surface对象,这个Surface对象是保在在一个关联的ViewRoot对象的成员变量mSurface中的,如图所示:
在应用程序进程这一侧,每一个Java层的Surface对都对应有一个C++层的Surface对象,并且后者的地址值保存在前者的成员变量mNativeSurface中。在WindowManagerService服务这一侧,每一个应用程序窗口,即每一个Activity组件,都有一个对应的WindowState对象,这个WindowState对象的成员变量mSurface同样是指向了一个Surface对象,如图所示:
在WindowManagerService服务这一侧,每一个Java层的Surface对都对应有一个C++层的SurfaceControl对象,并且后者的地址值保存在前者的成员变量mSurfaceControl中。
一个应用程序窗口分别位于应用程序进程和WindowManagerService服务中的两个Surface对象有什么区别呢?虽然它们都是用来操作位于SurfaceFlinger服务中的同一个Layer对象的,不过,它们的操作方式却不一样。具体来说,就是位于应用程序进程这一侧的Surface对象负责绘制应用程序窗口的UI,即往应用程序窗口的图形缓冲区填充UI数据,而位于WindowManagerService服务这一侧的Surface对象负责设置应用程序窗口的属性,例如位置、大小等属性。这两种不同的操作方式分别是通过C++层的Surface对象和SurfaceControl对象来完成的,因此,位于应用程序进程和WindowManagerService服务中的两个Surface对象的用法是有区别的。之所以会有这样的区别,是因为绘制应用程序窗口是独立的,由应用程序进程来完即可,而设置应用程序窗口的属性却需要全局考虑,即需要由WindowManagerService服务来统筹安排,例如,一个应用程序窗口的Z轴坐标大小要考虑它到的窗口类型以及它与系统中的其它窗口的关系。
由于一个应用程序窗口对应有两个Surface对象,那么它们是如何创建出来的呢?简单地说,就是按照以下步骤来创建:
- 应用程序进程请求WindowManagerService服务为一个应用程序窗口创建一个Surface对象;
- WindowManagerService服务请求SurfaceFlinger服务创建一个Layer对象,并且获得一个ISurface接口;
- WindowManagerService服务将获得的ISurface接口保存在其内部的一个Surface对象中,并且将该ISurface接口返回给应用程序进程;
- 应用程序进程得到WindowManagerService服务返回的ISurface接口之后,再将其封装成其内部的另外一个Surface对象中。
那么应用程序窗口的绘图表面又是什么时候创建的呢?一般是在不存在的时候就创建,因为应用程序窗口在运行的过程中,它的绘图表面会根据需要来销毁以及重新创建的,例如,应用程序窗口在第一次显示的时候,就会请求WindowManagerService服务为其创建绘制表面。当一个应用程序窗口被激活并且它的视图对象创建完成之后,应用程序进程就会调用与其所关联的一个ViewRoot对象的成员函数requestLayout来请求对其UI进行布局以及显示。由于这时候应用程序窗口的绘图表面尚未创建,因此,ViewRoot类的成员函数requestLayout就会请求WindowManagerService服务来创建绘图表面。接下来,我们就从ViewRoot类的成员函数requestLayout开始,分析应用程序窗口的绘图表面的创建过程。
Step 1. ViewRoot.requestLayout
public final class ViewRoot extends Handler implements ViewParent,
View.AttachInfo.Callbacks {
......
boolean mLayoutRequested;
......
public void requestLayout() {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
......
}
ViewRoot类的成员函数requestLayout首先调用另外一个成员函数checkThread来检查当前线程是否就是创建当前正在处理的ViewRoot对象的线程。如果不是的话,那么ViewRoot类的成员函数checkThread就会抛出一个异常出来。ViewRoot类是从Handler类继承下来的,用来处理应用程序窗口的UI布局和渲染等消息。由于这些消息都是与Ui相关的,因此它们就需要在UI线程中处理,这样我们就可以推断出当前正在处理的ViewRoot对象是要应用程序进程的UI线程中创建的。进一步地,我们就可以推断出ViewRoot类的成员函数checkThread实际上就是用来检查当前线程是否是应用程序进程的UI线程,如果不是的话,它就会抛出一个异常出来。
通过了上述检查之后,ViewRoot类的成员函数requestLayout首先将其成员变量mLayoutRequested的值设置为true,表示应用程序进程的UI线程正在被请求执行一个UI布局操作,接着再调用另外一个成员函数scheduleTraversals来继续执行UI布局的操作。
Step 2. ViewRoot.scheduleTraversals
public final class ViewRoot extends Handler implements ViewParent,
View.AttachInfo.Callbacks {
......
boolean mTraversalScheduled;
......
public void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
sendEmptyMessage(DO_TRAVERSAL);
}
}
......
}
ViewRoot类的成员变量mTraversalScheduled用来表示应用程序进程的UI线程是否已经调度了一个DO_TRAVERSAL消息。如果已经调度了的话,它的值就会等于true。在这种情况下, ViewRoot类的成员函数scheduleTraversals就什么也不做,否则的话,它就会首先将成员变量mTraversalScheduled的值设置为true,然后再调用从父类Handler继承下来的成员函数sendEmptyMessage来往应用程序进程的UI线程发送一个DO_TRAVERSAL消息。这个类型为DO_TRAVERSAL的消息是由ViewRoot类的成员函数performTraversals来处理的,因此,接下来我们就继续分析ViewRoot类的成员函数performTraversals的实现。
Step 3. ViewRoot.performTraversals
public final class ViewRoot extends Handler implements ViewParent,
View.AttachInfo.Callbacks {
......
View mView;
......
boolean mLayoutRequested;
boolean mFirst;
......
boolean mFullRedrawNeeded;
......
private final Surface mSurface = new Surface();
......
private void performTraversals() {
......
final View host = mView;
......
mTraversalScheduled = false;
......
boolean fullRedrawNeeded = mFullRedrawNeeded;
boolean newSurface = false;
......
if (mLayoutRequested) {
......
host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
.......
}
......
int relayoutResult = 0;
if (mFirst || windowShouldResize || insetsChanged
|| viewVisibilityChanged || params != null) {
......
boolean hadSurface = mSurface.isValid();
try {
......
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
......
if (!hadSurface) {
if (mSurface.isValid()) {
......
newSurface = true;
fullRedrawNeeded = true;
......
}
}
......
} catch (RemoteException e) {
}
......
}
final boolean didLayout = mLayoutRequested;
......
if (didLayout) {
mLayoutRequested = false;
......
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
......
}
......
mFirst = false;
......
boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();
if (!cancelDraw && !newSurface) {
mFullRedrawNeeded = false;
draw(fullRedrawNeeded);
......
} else {
......
// Try again
scheduleTraversals();
}
}
..