Android P WMS(9) --Surface

Android P WMS(1) -- wms简介

Android P WMS(2) -- wms初始化

Android O WMS(3) -- addwindow

Android P WMS(4) -- removewindow

Android P WMS(5) -- relayoutWindow

Android P WMS(6) -- windowanimator

Android P WMS(7) --wms 问题种类和debug技巧

Android P WMS(8) --View SYstem 简介

Android P WMS(9) --Surface

Surface的管理

Window不具有绘制能力,绘制还是交由surface来完成

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

//Surface还没有创建。
static final int NO_SURFACE = 0;
//Surface已经创建,但是窗口还没绘制,这时surface是隐藏的。
static final int DRAW_PENDING = 1;
//窗口已经完成了第一次绘制,但是surface还没有显示,Surface将会在下次layout时显示出来。
static final int COMMIT_DRAW_PENDING = 2;
//窗口的绘制请求已经提交,surface还没真正的显示,这通常用于延迟显示surface直到这个token中的所有窗口都已准备显示。
static final int READY_TO_SHOW = 3;
//窗口已经第一次在屏幕上显示出来。
static final int HAS_DRAWN = 4;

上面的几个状态,在我们使用layerdump时会非常有帮助

 

Surface的申请

WMS只负责窗口的层级和属性,surfaceflinger负责真正的将数据合成并显示到屏幕上。UI数据的绘制需要有画板,就是BufferQueue的支持,不管是那类窗口都要向surfaceflinger申请相应的layer,进一步得到缓冲区的使用权。这一切的启动是在viewroot中执行viewtree遍历时,会想WMS申请一个surface。
具体是从relayoutWindow开始,重新布局窗口,应用进程通过mWindowSession.relayout让WMS向surfaceflinger申请画板,然后通过最后一个参数mSurface将结果返回。

@/frameworks/base/core/java/android/view/ViewRootImpl.java
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
        boolean insetsPending) throws RemoteException {
    ...
    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,
            mPendingMergedConfiguration, mSurface);

    ...
    return relayoutResult;
}

 /frameworks/base/services/core/java/com/android/server/wm/Session.java
public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
        int requestedWidth, int requestedHeight, int viewFlags,
        int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
        Rect outVisibleInsets, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
        MergedConfiguration mergedConfiguration, Surface outSurface) {
    if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
            + Binder.getCallingPid());
    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
    int res = mService.relayoutWindow(this, window, seq, attrs,
            requestedWidth, requestedHeight, viewFlags, flags,
            outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
            outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface);
    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
            + Binder.getCallingPid());
    return res;
}

/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,) {
        ...
    synchronized(mWindowMap) {
        WindowState win = windowForClientLocked(session, client, false);  //1
      
        WindowStateAnimator winAnimator = win.mWinAnimator;  
        if (viewVisibility != View.GONE) {
            win.setRequestedSize(requestedWidth, requestedHeight);  //2
        }

        win.setFrameNumber(frameNumber);
        int attrChanges = 0;
        int flagChanges = 0;
        if (attrs != null) {
            mPolicy.adjustWindowParamsLw(win, attrs, hasStatusBarServicePermission);
            // if they don't have the permission, mask out the status bar bits
           ...
            flagChanges = win.mAttrs.flags ^= attrs.flags;
            attrChanges = win.mAttrs.copyFrom(attrs);   //3
          ...
        }

        if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility
                + " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
        ...
        mWindowPlacerLocked.performSurfacePlacement(true /* force */);      //4

        if (shouldRelayout) {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
            result = win.relayoutVisibleWindow(result, attrChanges, oldVisibility);
            try {
                result = createSurfaceControl(outSurface, result, win, winAnimator);  // 5
            } catch (Exception e) {
                mInputMonitor.updateInputWindowsLw(true /*force*/);

                Slog.w(TAG_WM, "Exception thrown when creating surface for client "
                         + client + " (" + win.mAttrs.getTitle() + ")",
                         e);
                Binder.restoreCallingIdentity(origId);
                return 0;
            }

        } else {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_2");
                ...
            if (viewVisibility == View.VISIBLE && winAnimator.hasSurface()) {
                    ...
                if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Releasing surface in: " + win);

                try {
                    Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wmReleaseOutSurface_"
                            + win.mAttrs.getTitle());
                    outSurface.release();
                } finally {
                    Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                }
            }
        }


        boolean toBeDisplayed = (result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0;
        final DisplayContent dc = win.getDisplayContent();
        if (imMayMove) {
            dc.computeImeTarget(true /* updateImeTarget */);
            if (toBeDisplayed) {
                dc.assignWindowLayers(false /* setLayoutNeeded */);  //6
            }
        }
        configChanged = updateOrientationFromAppTokensLocked(displayId);  //7
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);

        outFrame.set(win.mCompatFrame);  //8
        outOverscanInsets.set(win.mOverscanInsets);
        outContentInsets.set(win.mContentInsets);
     
        mInputMonitor.updateInputWindowsLw(true /*force*/);  //9
        if (DEBUG_LAYOUT) {
            Slog.v(TAG_WM, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString());
        }
        win.mInRelayout = false;
    }

    if (configChanged) {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: sendNewConfiguration");
        sendNewConfiguration(displayId);  //10
    }
    Binder.restoreCallingIdentity(origId);
    return result;
}
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);
    }
}

//管理Surface的mSurfaceControl变量是在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());

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);
 performSurfacePlacement间接调用了performSurfacePlacementInner。

//有些属性发生了变化,要在这里对变更做计算。
//针对每个窗口,根据需要应用特效,动画相关等。
    for (int i = windows.size() - 1; i >= 0; i--) {
        WindowState w = windows.get(i);
        w.applyDimLayerIfNeeded();
    }

 

参考:https://blog.csdn.net/lin20044140410/article/details/78798048

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值