在WindowManagerService服务这一侧,每一个应用程序窗口,即每一个Activity组件,都有一个对应的WindowState对象,这个WindowState对象的成员变量mSurface同样是指向了一个Surface对象
,如图3所示:
一个应用程序窗口分别位于应用程序进程和WindowManagerService服务中的两个Surface对象有什么区别呢?虽然它们都是用来操作位于SurfaceFlinger服务中的同一个Layer对象的,不过,它们的操作方式却不一样。具体来说,就是位于应用程序进程这一侧的Surface对象负责绘制应用程序窗口的UI,即往应用程序窗口的图形缓冲区填充UI数据,而位于WindowManagerService服务这一侧的Surface对象负责设置应用程序窗口的属性,例如位置、大小等属性。这两种不同的操作方式分别是通过C++层的Surface对象和SurfaceControl对象来完成的,因此,位于应用程序进程和WindowManagerService服务中的两个Surface对象的用法是有区别的。之所以会有这样的区别,是因为绘制应用程序窗口是独立的,由应用程序进程来完即可,而设置应用程序窗口的属性却需要全局考虑,即需要由WindowManagerService服务来统筹安排,例如,一个应用程序窗口的Z轴坐标大小要考虑它到的窗口类型以及它与系统中的其它窗口的关系。
Surface Surface
Surface SurfaceControl
应用程序窗口在第一次显示的时候,就会请求WindowManagerService服务为其创建绘制表面。
当一个应用程序窗口被激活并且它的视图对象创建完成之后,应用程序进程就会调用与其所关联的一个ViewRoot对象的成员函数requestLayout来请求对其UI进行布局以及显示。
WindowManagerService
ViewRoot request
public final class ViewRoot extends Handler implements ViewParent,
public void requestLayout() {
ViewRoot类是从Handler类继承下来的,用来处理应用程序窗口的UI布局和渲染等消息。
public void scheduleTraversals() {
private void performTraversals() {
final View host = mView;
boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();
attachInfo.mTreeObserver.dispatchOnPreDraw
ViewRoot类的成员函数performTraversals的实现是相当复杂的,这里我们分析它的实现框架,在以后的文章中,我们再详细分析它的实现细节。
在分析ViewRoot类的成员函数performTraversals的实现框架之前,我们首先了解ViewRoot类的以下五个成员变量:
--mView:它的类型为View,但它实际上指向的是一个DecorView对象,用来描述应用程序窗口的顶级视图,这一点可以参考前面Android应用程序窗口(Activity)的视图对象(View)的创建过程分析一文。
--mLayoutRequested:这是一个布尔变量,用来描述应用程序进程的UI线程是否需要正在被请求执行一个UI布局操作。
--mFirst:这是一个布尔变量,用来描述应用程序进程的UI线程是否第一次处理一个应用程序窗口的UI。
--mFullRedrawNeeded:这是一个布尔变量,用来描述应用程序进程的UI线程是否需要将一个应用程序窗口的全部区域都重新绘制。
--mSurface:它指向一个Java层的Surface对象,用来描述一个应用程序窗口的绘图表面。
scheduleTraversals performTraversals
mView DecorView
那么应用程序进程的UI线程就会调用另外一个成员函数relayoutWindow来请求WindowManagerService服务重新布局系统中的所有窗口。
ViewRoot
performTraversals
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
int relayoutResult = mWindowSession.relayout(
过在重绘之前,会先询问一下那些注册到当前正在处理的应用程序窗口中的Tree Observer,即调用它们的成员函数dispatchOnPreDraw,看看它们是否需要取消接下来的重绘操作,这个询问结果保存在本地变量cancelDraw中。
private final Surface mSurface = new Surface();
实现了IWindowSession接口的Binder代理对象是由IWindowSession.Stub.Proxy类来描述的,
接下来我们就继续分析它的成员函数relayout的实现。
IWindowSession IWindowSession.Stub.Proxy类
interface IWindowSession {
......
int relayout(IWindow window, in WindowManager.LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility,
boolean insetsPending, out Rect outFrame, out Rect outContentInsets,
out Rect outVisibleInsets, out Configuration outConfig,
out Surface outSurface);
......
}
这个接口定义在frameworks/base/core/java/android/view/IWindowSession.aidl文件
使用AIDL语言来描述的IWindowSession接口被编译后,就会生成一个使用Java语言来描述的IWindowSession.Stub.Proxy类,
它的成员函数relayout的实现如下所示:
AIDL
IWindowSession.aidl文件中。
Stub IWindowSession
Proxy IBinder mReadyToShow
relayout
Parcel.obtain
编译生成的文件
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/IWindowSession.java中。
IWindowSession.Stub.Proxy类的成员函数relayout首先将从前面传进来的各个参数写入到Parcel对象_data中,接着再通过其成员变量mRemote所描述的一个Binder代理对象向运行在WindowManagerService服务内部的一个Session对象发送一个类型为TRANSACTION_relayout的进程间通信请求,其中,这个Session对象是用来描述从当前应用程序进程到WindowManagerService服务的一个连接的。
当运行在WindowManagerService服务内部的Session对象处理完成当前应用程序进程发送过来的类型为TRANSACTION_relayout的进程间通信请求之后,就会将处理结果写入到Parcel对象_reply中,并且将这个Parcel对象_reply返回给当前应用程序进程处理。返回结果包含了一系列与参数window所描述的应用程序窗口相关的参数,如下所示:
1. 窗口的大小:最终保存在输出参数outFrame中。
2. 窗口的内容区域边衬大小:最终保存在输出参数outContentInsets中。
3. 窗口的可见区域边衬大小:最终保存在输出参数outVisibleInsets中。
4. 窗口的配置信息:最终保存在输出参数outConfig中。
5. 窗口的绘图表面:最终保存在输出参数outSurface中。
outSurface
public int relayoutWindow(Session session, IWindow client,
WindowManager.LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, boolean insetsPending,
Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
Configuration outConfig, Surface outSurface) {
WindowState win = windowForClientLocked(session, client, false);
WindowState mAppToken Activity
如果这个绘图表面能创建成功,那么WindowManagerService类的成员函数relayoutWindow就会将它的内容拷贝到输出参数outSource所描述的一个Surface对象去,以便可以将它返回给应用程序进程处理。
SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();
if (surfaceControl != null) {
outSurface.copyFrom(surfaceControl);
if (SHOW_TRANSACTIONS) Slog.i(TAG,
" OUT SURFACE " + outSurface + ": copied");
} else {
// For some reason there isn't a surface. Clear the
// caller's object so they see the same state.
outSurface.release();
}
mSurface = new Surface(
mSession.mSurfaceSession, mSession.mPid,
mAttrs.getTitle().toString(),
0, w, h, mAttrs.format, flags);
......
SurfaceSession
Surface
--mReportDestroySurface的值被设置为false。当一个应用程序窗口的绘图表面被销毁时,WindowManagerService服务就会将相应的WindowState对象的成员变量mReportDestroySurface的值设置为true,表示要向该应用程序窗口所运行在应用程序进程发送一个绘图表面销毁通知。
--mSurfacePendingDestroy的值被设置为false。当一个应用程序窗口的绘图表面正在等待销毁时,WindowManagerService服务就会将相应的WindowState对象的成员变量mReportDestroySurface的值设置为true。
绘图表面
--如果成员变量mAppToken的值不等于null,那么就需要将它所描述的一个AppWindowToken对象的成员变量allDrawn的值设置为false。从前面Android应用程序窗口(Activity)与WindowManagerService服务的连接过程分析一文可以知道,一个AppWindowToken对象用来描述一个Activity组件的,当该AppWindowToken对象的成员变量allDrawn的值等于true时,就表示属于该Activity组件的所有窗口都已经绘制完成了。
public class Surface implements Parcelable {
......
private int mSurfaceControl;
......
private Canvas mCanvas;
......
private String mName;
......
public Surface(SurfaceSession s,
int pid, String name, int display, int w, int h, int format, int flags)
throws OutOfResourcesException {
......
mCanvas = new CompatibleCanvas();
init(s,pid,name,display,w,h,format,flags);
mName = name;
}
......
private native void init(SurfaceSession s,
int pid, String name, int display, int w, int h, int format, int flags)
throws OutOfResourcesException;
......
}
mSurfaceControl
static void Surface_init(
JNIEnv* env, jobject clazz,
jobject session,
jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jint flags)
{
if (session == NULL) {
doThrow(env, "java/lang/NullPointerException");
return;
}
SurfaceComposerClient* client =
(SurfaceComposerClient*)env->GetIntField(session, sso.client);
sp
if (jname == NULL) {
surface = client->createSurface(pid, dpy, w, h, format, flags);
} else {
const jchar* str = env->GetStringCritical(jname, 0);
const String8 name(str, env->GetStringLength(jname));
env->ReleaseStringCritical(jname, str);
surface = client->createSurface(pid, name, dpy, w, h, format, flags);
}
if (surface == 0) {
doThrow(env, OutOfResourcesException);
return;
}
setSurfaceControl(env, clazz, surface);
}
SurfaceComposerClient*
WindowManagerService
DecorView