Android 7.1 GUI系统-窗口管理WMS-Surface管理(四)

时间:2022-05-17 03:55:39

Surface的管理

Surface是窗口能真正显示到物理屏幕上的基础,由surfaceflinger管理,可以通过WindowStateAnimator.java中的变量mDrawState来查看每个窗口相关的surface的状态。

surface5中状态:

WindowStateAnimator.java

//Surface还没有创建。

staticfinal int NO_SURFACE = 0;

//Surface已经创建,但是窗口还没绘制,这时surface是隐藏的。

staticfinal int DRAW_PENDING = 1;

//窗口已经完成了第一次绘制,但是surface还没有显示,Surface将会在下次layout时显示出来。

staticfinal int COMMIT_DRAW_PENDING = 2;

//窗口的绘制请求已经提交,surface还没真正的显示,这通常用于延迟显示surface直到这个token中的所有窗口都已准备显示。

staticfinal int READY_TO_SHOW = 3;

//窗口已经第一次在屏幕上显示出来。

staticfinal int HAS_DRAWN = 4;


String drawStateToString() @WindowStateAnimator.java{
switch (mDrawState) {
case NO_SURFACE: return "NO_SURFACE";
case DRAW_PENDING: return "DRAW_PENDING";
case COMMIT_DRAW_PENDING: return "COMMIT_DRAW_PENDING";
case READY_TO_SHOW: return "READY_TO_SHOW";
case HAS_DRAWN: return "HAS_DRAWN";
default: return Integer.toString(mDrawState);
}
}
int mDrawState;

1),Surface的申请

WMS只负责窗口的层级和属性,surfaceflinger负责真正的将数据合成并显示到屏幕上。UI数据的绘制需要有画板,就是BufferQueue的支持,不管是那类窗口都要向surfaceflinger申请相应的layer,进一步得到缓冲区的使用权。这一切的启动是在viewroot执行viewtree遍历时,会想WMS申请一个surface


具体是从relayoutWindow开始重新布局窗口,应用进程通过mWindowSession.relayoutWMSsurfaceflinger申请画板,然后通过最后一个参数mSurface将结果返回

final Surface mSurface = new Surface();
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException@ViewRootImpl.java {
int relayoutResult = mWindowSession.relayout(
mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
mSurface);
}

接着看surface是怎么申请的,先看IwindowSession中的处理

public int relayout(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, int flags, android.graphics.Rect outFrame, android.graphics.Rect outOverscanInsets, android.graphics.Rect outContentInsets, android.graphics.Rect outVisibleInsets, android.graphics.Rect outStableInsets, android.graphics.Rect outOutsets, android.graphics.Rect outBackdropFrame, android.content.res.Configuration outConfig, android.view.Surface outSurface) throws android.os.RemoteException
@IwindowSession.java$IWindowSession$Stub$Proxy{
//通过Binder向服务端发送请求TRANSACTION_relayout,
mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply, 0);
//收到恢复后,从reply中取出结果,这是客户端的实现,具体取出的是什么,就要看服务端写入的什么了。
outSurface.readFromParcel(_reply);
}

//看服务端的处理

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
@IwindowSession.java$IWindowSession$Stub{
switch (code){
//跟客户端相同的业务码TRANSACTION_relayout
case TRANSACTION_relayout:
{
//服务器端,首先创建了一个surface对象,然后调用WMS的relayoutWindow函数为这个对象赋值,最后通过_arg15.writeToParcel把结果写入回复的parcel中。如果一个类想在aidl机制中,客户度与服务端之间传递,就要继承Parcelable接口,并实现writeToParcel方法。
android.view.Surface _arg15;
_arg15 = new android.view.Surface();
//这里会调用服务端Session.java中的实现,进一步调用WMS中的relayoutWindow。
int _result = this.relayout(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11,
_arg12, _arg13, _arg14, _arg15);
_arg15.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
}
}

public int relayoutWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, int flags,
Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
Configuration outConfig, Surface outSurface) @WindowManagerService.java{
//每个windowState都有一个mWinAnimator来处理窗口的退出和进入动画。
WindowStateAnimator winAnimator = win.mWinAnimator;
//设置用户请求的宽、高,这值也会影响到surface的属性。
win.setRequestedSize(requestedWidth, requestedHeight);
//生成surface对象,通过outSurface.copyFrom返回客户端。
result = createSurfaceControl(outSurface, result, win, winAnimator);

updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
false /*updateInputWindows*/)

mWindowPlacerLocked.performSurfacePlacement();
}

WMS并没有直接生成surface的操作,继续跟踪createSurfaceControl

private int createSurfaceControl(Surface outSurface, int result, WindowState win,
WindowStateAnimator winAnimator) @WindowManagerService.java{
// createSurfaceLocked将会生成一个真正的surface,并有SurfaceControl来管理。
WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked();
if (surfaceController != null) {
surfaceController.getSurface(outSurface);
}
}

//管理SurfacemSurfaceControl变量是在WindowSurfaceController的构造函数中生成的。

WindowSurfaceController createSurfaceLocked() @WindowStateAnimator.java{
mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
attrs.getTitle().toString(),
width, height, format, flags, this);
}

接着看SurfaceControl的构造函数。

long mNativeObject;
public SurfaceControl(SurfaceSession session,
String name, int w, int h, int format, int flags){
//调用的nativeCreate函数,将会建立跟SurfaceFlinger的联系。
mNativeObject = nativeCreate(session, name, w, h, format, flags);
}

static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,        jstring nameStr, jint w, jint h, jint format, jint flags) @android_view_SurfaceControl.cpp{// SurfaceComposerClient是surfaceflinger的代表,opengl es和surface都是在这个类的协助下申请和访问buffer缓冲区。这里是通过 android_view_SurfaceSession_getClient来获取client对象,那么是什么地方创建的呢?	sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));	sp<SurfaceControl> surface = client->createSurface( String8(name.c_str()), w, h, format, flags);	surface->incStrong((void *)nativeCreate);	return reinterpret_cast<jlong>(surface.get());}

继续看哪里创建了clientSurfaceComposerClient)对象。从这个函数的实现,可以知道,这是从jni层获取java层的属性,所以创建相关类实例的地方应该在native层创建了对象,然后通过jni保存在了java层。

sp<SurfaceComposerClient> android_view_SurfaceSession_getClient(
JNIEnv* env, jobject surfaceSessionObj) @android_view_SurfaceSession.cpp{
return reinterpret_cast<SurfaceComposerClient*>(
env->GetLongField(surfaceSessionObj, gSurfaceSessionClassInfo.mNativeClient));
}

具体过程,还要从addWindow看起。

public int addWindow(…...)@WindowManagerService.java{
//创建WindowState时,将session变量保存在WindowState 的变量mSession中。
WindowState win = new WindowState(this, session, client, token…);
//attach()的实现中,调用mSession的windowAddedLocked()方法。进一步生成了SurfaceSession实例mSurfaceSession(属于Session.java的变量)。
win.attach();
}

//SurfaceSession的构造函数中,通过native方法创建一个到SurfaceFlinger的连接,就是SurfaceComposerClient实例,这是nativeSurfaceComposerClient.cpp对象,这个对象保存在了SurfaceSession.java中的变量mNativeClient中。

private long mNativeClient; // SurfaceComposerClient*
public SurfaceSession() @SurfaceSession.java{
mNativeClient = nativeCreate();
}

在创建WindowState对象时,其构造函数中,同时创建了WindowStateAnimator对象,而且WindowStateAnimator.java的构造函数中也保存了Session对象到其变量mSession中。

WindowStateAnimator(final WindowState win) @WindowStateAnimator.java{
mSession = win.mSession;
}

在调用WindowStateAnimatorcreateSurfaceLocked函数,创建WindowSurfaceController对象时,把mSession.mSurfaceSession传给了WindowSurfaceController的构造函数,在WindowSurfaceController的构造函数中,这个SurfaceSession对象传给了SurfaceControl

现在我们直到SurfaceControl.java调用native函数nativeCreate时,获取的SurfaceComposerClient实例client是怎么来的了。


前面说了Surface是有SurfaceControl来管理的,SurfaceControl.java构造函数的nativeCreate就是建立跟surfaceflinger的连接,最终的surface的创建还要有SurfaceFlinger来完成。

sp<SurfaceControl> SurfaceComposerClient::createSurface(
const String8& name,
uint32_t w,
uint32_t h,
PixelFormat format,
uint32_t flags)@SurfaceComposerClient.cpp{
sp<IGraphicBufferProducer> gbp;
//调用Client.cpp的实现,创建IGraphicBufferProducer实例。
status_t err = mClient->createSurface(name, w, h, format, flags,
&handle, &gbp);
//生成native层的 SurfaceControl对象,同时传入IGraphicBufferProducer对象。
sur = new SurfaceControl(this, handle, gbp);
}


回头看前面createSurfaceControl函数中获取surface的方式是surfaceControllerWindowSurfaceController.java)的getSurface(outSurface);这个java层方法最终会调用SurfaceControl.cpp中的getSurface方法。

sp<Surface> SurfaceControl::getSurface() const @SurfaceControl.cpp{
mSurfaceData = new Surface(mGraphicBufferProducer, false);
return mSurfaceData;
}

可以看到这里创建了真正的Surface对象,当然这里的对象还是在server端,然后会通过writeToParcel写入reply。这样ViewRootImpl.java这边,也即是客户端就可以利用readFromParcel把它还原出来,实现了对ViewRootImpl.javamSurface变量的填充。

public int relayout(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs, int requestedWidth, int requestedHeight, int viewVisibility, int flags, android.graphics.Rect outFrame, android.graphics.Rect outOverscanInsets, android.graphics.Rect outContentInsets, android.graphics.Rect outVisibleInsets, android.graphics.Rect outStableInsets, android.graphics.Rect outOutsets, android.graphics.Rect outBackdropFrame, android.content.res.Configuration outConfig, android.view.Surface outSurface) throws android.os.RemoteException@IWindowSession.java{
//这里就是读取server端的返回值。Surface.java中的 readFromParcel调用了native层的实现nativeReadFromParcel。
outSurface.readFromParcel(_reply);
}

//可以看到客户端新创建了native层的Surface对象,所以和服务端的surface(native)对象并不是同一个,但是跟surface关联的IGraphicBufferProducer是同一个,实际上Surface的主要职责就是管理用于存储UI数据的内存块。

static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
jlong nativeObject, jobject parcelObj) @android_view_Surface.cpp{
Parcel* parcel = parcelForJavaObject(env, parcelObj);
android::view::Surface surfaceShim;
surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
sp<Surface> sur;
sur = new Surface(surfaceShim.graphicBufferProducer, true);
sur->incStrong(&sRefBaseOwner);
return jlong(sur.get());
}


2),relayoutWindow中还有一个比较重要的调用performSurfacePlacement,功能包括两部分,一是performLayout,计算窗口大小,二是performSurface,对Surface属性的设置,如:setSizesetLayersetPostion,然后这些变更会告知Surfaceflinger


public int relayoutWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int requestedWidth,
int requestedHeight, int viewVisibility, int flags,
Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
Configuration outConfig, Surface outSurface)@WindowManagerService.java {
mWindowPlacerLocked.performSurfacePlacement();
}

performSurfacePlacement间接调用了performSurfacePlacementInner

//有些属性发生了变化,要在这里对变更做计算。

private void performSurfacePlacementInner(boolean recoveringMemory) @WindowSurfacePlacer.java{
//在处理surface属性前,先调用 openTransaction,然后对surface属性做处理,但是处理不是立即生效,而是要等到 closeTransaction业务关闭后,统一告知surfaceflinger才会生效。
SurfaceControl.openTransaction();
try {
applySurfaceChangesTransaction(recoveringMemory, numDisplays, defaultDw, defaultDh);
}finally {
SurfaceControl.closeTransaction();
}
//获取默认显示屏的窗口列表。
final WindowList defaultWindows = defaultDisplay.getWindowList();

//处理应用切换mService.mAppTransition相关的操作。
defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
defaultDisplay.pendingLayoutChanges |=mService.handleAnimatingStoppedAndTransitionLocked();
//如果窗口不可见了,销毁他的surface。
boolean wallpaperDestroyed = false;
i = mService.mDestroySurface.size();
if (i > 0) {
//这里有while循环,处理mDestroySurface列表中的每个 WindowState。
WindowState win = mService.mDestroySurface.get(i);
win.destroyOrSaveSurface();
mService.mDestroySurface.clear();
}

//移除不在具有可见窗口的token。
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
for (i = exitingTokens.size() - 1; i >= 0; i--) {
WindowToken token = exitingTokens.get(i);
exitingTokens.remove(i);
mWallpaperControllerLocked.removeWallpaperToken(token);
}
}

//从task中移除退出的应用程序。
for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
final AppTokenList exitingAppTokens =
mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
AppWindowToken token = exitingAppTokens.get(i);
token.mAppAnimator.clearAnimation();
token.removeAppFromTaskLocked();
}

//更新窗口信息到Inputdispatch,因为现在窗口更改已经稳定了。
mService.mInputMonitor.updateInputWindowsLw(true /*force*/);

//安排动画的执行。
mService.scheduleAnimationLocked();
}

private void applySurfaceChangesTransaction(boolean recoveringMemory, int numDisplays,            int defaultDw, int defaultDh) @WindowSurfacePlacer.java{//循环处理每个显示设备,我们只关注主显示屏,	final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);	WindowList windows = displayContent.getWindowList();	DisplayInfo displayInfo = displayContent.getDisplayInfo();	int repeats = 0;	do {//while循环,6次后跳出,为什么是6次不知道?		repeats++;		if (repeats > 6) {			displayContent.layoutNeeded = false;			break;		}//需要的化,计算窗口大小,这个 LAYOUT_REPEAT_THRESHOLD是4,定义在WindowManagerService.java中。		if (repeats < LAYOUT_REPEAT_THRESHOLD) {			performLayoutLockedInner(displayContent, repeats == 1,false /* updateInputWindows */);		}		if (isDefaultDisplay) {//对每一个窗口,调用窗口策略policy(PhoneWindowManager.java)中的方法,应用policy。			mService.mPolicy.beginPostLayoutPolicyLw(dw, dh);			for (int i = windows.size() - 1; i >= 0; i--) {				WindowState w = windows.get(i);				if (w.mHasSurface) {					mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs,						w.mAttachedWindow);				}			}			displayContent.pendingLayoutChanges |=mService.mPolicy.finishPostLayoutPolicyLw();		}	}while (displayContent.pendingLayoutChanges != 0);//针对每个窗口,根据需要应用特效,动画相关等。	for (int i = windows.size() - 1; i >= 0; i--) {		WindowState w = windows.get(i);		w.applyDimLayerIfNeeded();	}}