Android14 WMS-窗口绘制之relayoutWindow流程(二)-Server端

本文接着如下文章往下讲

Android14 WMS-窗口绘制之relayoutWindow流程(一)-Client端-CSDN博客

然后就到了Server端WMS的核心实现方法relayoutWindow里29f881a37fcb498095f0b6ace978d5e4.jpg  

WindowManagerService.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
...
    public int relayoutWindow(Session session, IWindow client, LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewVisibility, int flags, int seq,
            int lastSyncSeqId, ClientWindowFrames outFrames,
            MergedConfiguration outMergedConfiguration, SurfaceControl outSurfaceControl,
            InsetsState outInsetsState, InsetsSourceControl.Array outActiveControls,
            Bundle outSyncIdBundle) {

  由于此方法太长,所以分开讲述

1. 第一步

        if (outActiveControls != null) {
            outActiveControls.set(null);
        }
        int result = 0;
        boolean configChanged = false;
//获取发起者的Uid和Pid
        final int pid = Binder.getCallingPid();
        final int uid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        synchronized (mGlobalLock) {
//通过IBinder client查询mWindowMap中对应的WindowState 
            final WindowState win = windowForClientLocked(session, client, false);
            if (win == null) {
                return 0;
            }
            if (win.mRelayoutSeq < seq) {
                win.mRelayoutSeq = seq;
            } else if (win.mRelayoutSeq > seq) {
                return 0;
            }

            if (win.cancelAndRedraw() && win.mPrepareSyncSeqId <= lastSyncSeqId) {
                // The client has reported the sync draw, but we haven't finished it yet.
                // Don't let the client perform a non-sync draw at this time.
                result |= RELAYOUT_RES_CANCEL_AND_REDRAW;
            }
//获取window对应的DisplayContent 
            final DisplayContent displayContent = win.getDisplayContent();
//获取window对应的DisplayPolicy 
            final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
//获取window对应的WindowStateAnimator 
            WindowStateAnimator winAnimator = win.mWinAnimator;
            if (viewVisibility != View.GONE) {
//如果不是Gone,则更新全局变量之窗口申请的宽高 mRequestedWidth mRequestedHeight 
                win.setRequestedSize(requestedWidth, requestedHeight);
            }

2. 第二步

            int attrChanges = 0;
            int flagChanges = 0;
            int privateFlagChanges = 0;
//如果窗口的属性不为空,则说明有要更新的窗口属性
            if (attrs != null) {
//调整窗口参数,主要是针对某些窗口类型,清理一些窗口属性参数
                displayPolicy.adjustWindowParamsLw(win, attrs);
...
窗口type在窗口add之后不能被改变,否则就会异常,窗口type是区分窗口层级很重要的一个东西
                if (win.mAttrs.type != attrs.type) {
                    throw new IllegalArgumentException(
                            "Window type can not be changed after the window is added.");
                }
...
//异或^     两个位相同为0,相异为1
                flagChanges = win.mAttrs.flags ^ attrs.flags;
                privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags;
                attrChanges = win.mAttrs.copyFrom(attrs);
                final boolean layoutChanged =
                        (attrChanges & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0;
                if (layoutChanged || (attrChanges
                        & WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED) != 0) {
窗口布局有变化,需要更新
                    win.mLayoutNeeded = true;
                }
                if (layoutChanged && win.providesDisplayDecorInsets()) {
                    configChanged = displayPolicy.updateDecorInsetsInfo();
                }
//看下有没有锁屏相关的flag变化
                if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0
                        || (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) {
                    win.mActivityRecord.checkKeyguardFlagsChanged();
                }

                if ((privateFlagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
                    updateNonSystemOverlayWindowsVisibilityIfNeeded(
                            win, win.mWinAnimator.getShown());
                }
                if ((attrChanges & (WindowManager.LayoutParams.PRIVATE_FLAGS_CHANGED)) != 0) {
                    winAnimator.setColorSpaceAgnosticLocked((win.mAttrs.privateFlags
                            & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
                }
...
            }

3. 第三步

            int attrChanges = 0;
            int flagChanges = 0;
            int privateFlagChanges = 0;
//如果窗口的属性不为空,则说明有要更新的窗口属性
            if (attrs != null) {
//调整窗口参数,主要是针对某些窗口类型,清理一些窗口属性参数
                displayPolicy.adjustWindowParamsLw(win, attrs);
...
窗口type在窗口add之后不能被改变,否则就会异常,窗口type是区分窗口层级很重要的一个东西
                if (win.mAttrs.type != attrs.type) {
                    throw new IllegalArgumentException(
                            "Window type can not be changed after the window is added.");
                }
...
//异或^     两个位相同为0,相异为1
                flagChanges = win.mAttrs.flags ^ attrs.flags;
                privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags;
                attrChanges = win.mAttrs.copyFrom(attrs);
                final boolean layoutChanged =
                        (attrChanges & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0;
                if (layoutChanged || (attrChanges
                        & WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED) != 0) {
窗口布局有变化,需要更新
                    win.mLayoutNeeded = true;
                }
                if (layoutChanged && win.providesDisplayDecorInsets()) {
                    configChanged = displayPolicy.updateDecorInsetsInfo();
                }
//看下有没有锁屏相关的flag变化
                if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0
                        || (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) {
                    win.mActivityRecord.checkKeyguardFlagsChanged();
                }

                if ((privateFlagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
                    updateNonSystemOverlayWindowsVisibilityIfNeeded(
                            win, win.mWinAnimator.getShown());
                }
                if ((attrChanges & (WindowManager.LayoutParams.PRIVATE_FLAGS_CHANGED)) != 0) {
                    winAnimator.setColorSpaceAgnosticLocked((win.mAttrs.privateFlags
                            & WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
                }
...
            }

4. 第四步

//06-01 10:12:18.006  1890  2256 V WindowManager: Relayout Window{8d0d088 u0 
//com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: 
//viewVisibility=0 req=7104x3840 {(0,0)(fillxfill) sim={adjust=resize forwardNavigation} 
//ty=BASE_APPLICATION wanim=0x10302f2
//06-01 10:12:18.006  1890  2256 V WindowManager:   fl=LAYOUT_IN_SCREEN //LAYOUT_INSET_DECOR 
//SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
//06-01 10:12:18.006  1890  2256 V WindowManager:   pfl=NO_MOVE_ANIMATION 
//FORCE_DRAW_STATUS_BAR_BACKGROUND HIDE_NON_SYSTEM_OVERLAY_WINDOWS USE_BLAST 
//FIT_INSETS_CONTROLLED
//06-01 10:12:18.006  1890  2256 V WindowManager:   vsysui=LIGHT_STATUS_BAR 
//LIGHT_NAVIGATION_BAR
//06-01 10:12:18.006  1890  2256 V WindowManager:   apr=LIGHT_STATUS_BARS 
//LIGHT_NAVIGATION_BARS
//06-01 10:12:18.006  1890  2256 V WindowManager:   bhv=DEFAULT
//06-01 10:12:18.006  1890  2256 V WindowManager:   fitSides=}

           if (DEBUG_LAYOUT) Slog.v(TAG_WM, "Relayout " + win + ": viewVisibility=" + viewVisibility
                    + " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
            if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
                winAnimator.mAlpha = attrs.alpha;
            }
//设置窗口大小
            win.setWindowScale(win.mRequestedWidth, win.mRequestedHeight);

            if (win.mAttrs.surfaceInsets.left != 0
                    || win.mAttrs.surfaceInsets.top != 0
                    || win.mAttrs.surfaceInsets.right != 0
                    || win.mAttrs.surfaceInsets.bottom != 0) {
                winAnimator.setOpaqueLocked(false);
            }

            final int oldVisibility = win.mViewVisibility;

            // If the window is becoming visible, visibleOrAdding may change which may in turn
            // change the IME target.
//窗口由不可见/Gone变为可见
            final boolean becameVisible =
                    (oldVisibility == View.INVISIBLE || oldVisibility == View.GONE)
                            && viewVisibility == View.VISIBLE;
            boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0
                    || becameVisible;
//窗口焦点更新--当之前的可见性和现在不一致,并且窗口没有携带FLAG_NOT_FOCUSABLE,并且mRelayoutCalled为false
            boolean focusMayChange = win.mViewVisibility != viewVisibility
                    || ((flagChanges & FLAG_NOT_FOCUSABLE) != 0)
                    || (!win.mRelayoutCalled);

            boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
                    && win.hasWallpaper();
            wallpaperMayMove |= (flagChanges & FLAG_SHOW_WALLPAPER) != 0;
            if ((flagChanges & FLAG_SECURE) != 0 && winAnimator.mSurfaceController != null) {
                winAnimator.mSurfaceController.setSecure(win.isSecureLocked());
            }

            final boolean wasVisible = win.isVisible();

            win.mRelayoutCalled = true;
            win.mInRelayout = true;
//设置窗口可见性为申请的可见性,可见则viewVisibility=0
            win.setViewVisibility(viewVisibility);
            ProtoLog.i(WM_DEBUG_SCREEN_ON,
                    "Relayout %s: oldVis=%d newVis=%d. %s", win, oldVisibility,
                            viewVisibility, new RuntimeException().fillInStackTrace());
//06-01 10:12:18.008  1890  2256 W WindowManager: setLayoutNeeded: 
//callers=com.android.server.wm.WindowState.setDisplayLayoutNeeded:2671 
//com.android.server.wm.WindowManagerService.relayoutWindow:2419 
//com.android.server.wm.Session.relayout:249 
            win.setDisplayLayoutNeeded();
            win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
 

viewVisibility代表当前View的可见性

mViewVisibility Vlaue 含义
VISIBLE 0x00000000

这个视图可见

与#setVisibility和#attr_android:visibility" android:visibility}一起使用。

INVISIBLE 0x00000004

这个视图不可见

与#setVisibility和#attr_android:visibility" android:visibility}一起使用。

GONE 0x00000008

这个视图是不可见的,它不占用任何空间进行布局

与#setVisibility和#attr_android:visibility" android:visibility}一起使用。

5. 第五步 创建Surface图层流程

            // We should only relayout if the view is visible, it is a starting window, or the
            // associated appToken is not hidden.
//只有当视图可见、并且它是STARTING窗口或关联的 appToken 未隐藏时,我们才应该重新布局。
            final boolean shouldRelayout = viewVisibility == View.VISIBLE &&
                    (win.mActivityRecord == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
                            || win.mActivityRecord.isClientVisible());
            // If we are not currently running the exit animation, we need to see about starting
            // one.
            // This must be called before the call to performSurfacePlacement.
//如果我们当前没有运行退出动画,满足下列条件,则需执行退出动画
            if (!shouldRelayout && winAnimator.hasSurface() && !win.mAnimatingExit) {
                if (DEBUG_VISIBILITY) {
//06-01 10:12:14.228  1890  2256 I WindowManager: Relayout invis Window{8c33950 u0 
//NotificationShade}: mAnimatingExit=false
                    Slog.i(TAG_WM,
                            "Relayout invis " + win + ": mAnimatingExit=" + win.mAnimatingExit);
                }
                result |= RELAYOUT_RES_SURFACE_CHANGED;
                // When FLAG_SHOW_WALLPAPER flag is removed from a window, we usually set a flag
                // in DC#pendingLayoutChanges and update the wallpaper target later.
                // However it's possible that FLAG_SHOW_WALLPAPER flag is removed from a window
                // when the window is about to exit, so we update the wallpaper target
                // immediately here. Otherwise this window will be stuck in exiting and its
                // surface remains on the screen.
                // TODO(b/189856716): Allow destroying surface even if it belongs to the
                //  keyguard target.
                if (wallpaperMayMove) {
                    displayContent.mWallpaperController.adjustWallpaperWindows();
                }
//执行窗口退出动画
                tryStartExitingAnimation(win, winAnimator);
            }

            // Create surfaceControl before surface placement otherwise layout will be skipped
            // (because WS.isGoneForLayout() is true when there is no surface.
//outSurfaceControl是client端传入的,在ViewRootImpl全局变量中就实例化好了
//http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/view/ViewRootImpl.java#708
//private final SurfaceControl mSurfaceControl = new SurfaceControl();
//所以这个不会为空
            if (shouldRelayout && outSurfaceControl != null) {
                try {
//创建图层
                    result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
                } catch (Exception e) {
                    displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);

                    ProtoLog.w(WM_ERROR,
                            "Exception thrown when creating surface for client %s (%s). %s",
                            client, win.mAttrs.getTitle(), e);
                    Binder.restoreCallingIdentity(origId);
                    return 0;
                }
            }
 

5.1 WindowManagerService#createSurfaceControl

WindowManagerService.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    private int createSurfaceControl(SurfaceControl outSurfaceControl, int result,
            WindowState win, WindowStateAnimator winAnimator) {
        if (!win.mHasSurface) {
            result |= RELAYOUT_RES_SURFACE_CHANGED;
        }

        WindowSurfaceController surfaceController;
        try {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
//创建window对应的surface图层
            surfaceController = winAnimator.createSurfaceLocked();
...
        if (surfaceController != null) {
            surfaceController.getSurfaceControl(outSurfaceControl);
            ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);

        } else {
...
    }

 5.2  WindowStateAnimator#createSurfaceLocked

WindowStateAnimator.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java

    WindowSurfaceController createSurfaceLocked() {
        final WindowState w = mWin;

        if (mSurfaceController != null) {
            return mSurfaceController;
        }
//设置是否有Surface标志位为false
        w.setHasSurface(false);

        ProtoLog.i(WM_DEBUG_ANIM, "createSurface %s: mDrawState=DRAW_PENDING", this);
//重置图层绘制状态
        resetDrawState();
//要开始绘制图层了,要先freeze(冻住)住屏幕,等待绘制完成再Unfreeze,这里有个超时机制,即
//冻住屏幕有个最大时间WINDOW_FREEZE_TIMEOUT_DURATION--2000ms
        mService.makeWindowFreezingScreenIfNeededLocked(w);

        int flags = SurfaceControl.HIDDEN;
        final WindowManager.LayoutParams attrs = w.mAttrs;
//如果window是加密窗口,则添加此flag
        if (w.isSecureLocked()) {
            flags |= SurfaceControl.SECURE;
        }

        if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {
            flags |= SurfaceControl.SKIP_SCREENSHOT;
        }
//06-01 10:12:18.009  1890  2256 V WindowManager: Creating surface in session 
//android.view.SurfaceSession@fcb7984 window WindowStateAnimator{31728a0 
//com.android.settings/com.android.settings.homepage.SettingsHomepageActivity} format=-1 
//flags=4
        if (DEBUG_VISIBILITY) {
            Slog.v(TAG, "Creating surface in session "
                    + mSession.mSurfaceSession + " window " + this
                    + " format=" + attrs.format + " flags=" + flags);
        }

        // Set up surface control with initial size.
        try {

            // This can be removed once we move all Buffer Layers to use BLAST.
            final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
            final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
//创建图层----创建WindowSurfaceController,主要是管理图层的,可设置图层位置,大小,是否可见等 
            mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), format,
                    flags, this, attrs.type);
//将 Surface 设置为与颜色空间无关。
            mSurfaceController.setColorSpaceAgnostic(w.getPendingTransaction(),
                    (attrs.privateFlags & LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
//图层创建好了,更新是否有Surface的标志位为true
            w.setHasSurface(true);
...
//06-01 10:12:18.015  1890  2256 V WindowManager: Got surface: 
//Surface(name=com.android.settings/com.android.settings.homepage.SettingsHomepageActivit//y)@0xafd3c59, set left=0 top=0
        if (DEBUG) {
            Slog.v(TAG, "Got surface: " + mSurfaceController
                    + ", set left=" + w.getFrame().left + " top=" + w.getFrame().top);
        }
...
        mLastHidden = true;
//06-01 10:12:18.015  1890  2256 V WindowManager: Created surface 
//WindowStateAnimator{31728a0 
//com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}
        if (DEBUG) Slog.v(TAG, "Created surface " + this);
        return mSurfaceController;
    }

  5.3 WindowSurfaceController之创建图层

    WindowSurfaceController(String name, int format, int flags, WindowStateAnimator animator,
            int windowType) {
        mAnimator = animator;

        title = name;

        mService = animator.mService;
        final WindowState win = animator.mWin;
        mWindowType = windowType;
        mWindowSession = win.mSession;

        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl");
//创建图层
        final SurfaceControl.Builder b = win.makeSurface()
                .setParent(win.getSurfaceControl())
                .setName(name)
                .setFormat(format)
                .setFlags(flags)
                .setMetadata(METADATA_WINDOW_TYPE, windowType)
                .setMetadata(METADATA_OWNER_UID, mWindowSession.mUid)
                .setMetadata(METADATA_OWNER_PID, mWindowSession.mPid)
                .setCallsite("WindowSurfaceController");

        final boolean useBLAST = mService.mUseBLAST && ((win.getAttrs().privateFlags
                & WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST) != 0);

        if (useBLAST) {
            b.setBLASTLayer();
        }

        mSurfaceControl = b.build();

        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
-------------------------------------------------------------------
//http://aospxref.com/android-14.0.0_r2/xref/frameworks/base/core/java/android/view/SurfaceControl.java#857

    public static class Builder {
        /**
         * Begin building a SurfaceControl.
         */
        public Builder() {
        }

        /**
         * Construct a new {@link SurfaceControl} with the set parameters. The builder
         * remains valid.
         */
        @NonNull
        public SurfaceControl build() {
            if (mWidth < 0 || mHeight < 0) {
                throw new IllegalStateException(
                        "width and height must be positive or unset");
            }
            if ((mWidth > 0 || mHeight > 0) && (isEffectLayer() || isContainerLayer())) {
                throw new IllegalStateException(
                        "Only buffer layers can set a valid buffer size.");
            }

            if (mName == null) {
                Log.w(TAG, "Missing name for SurfaceControl", new Throwable());
            }

            if ((mFlags & FX_SURFACE_MASK) == FX_SURFACE_NORMAL) {
                setBLASTLayer();
            }

            return new SurfaceControl(
                    mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,
                    mLocalOwnerView, mCallsite);
        }

---------------------------------------------------------
    private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
            SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,
            String callsite)
                    throws OutOfResourcesException, IllegalArgumentException {
        if (name == null) {
            throw new IllegalArgumentException("name must not be null");
        }

        mName = name;
        mWidth = w;
        mHeight = h;
        mLocalOwnerView = localOwnerView;
        Parcel metaParcel = Parcel.obtain();
        long nativeObject = 0;
        try {
            if (metadata != null && metadata.size() > 0) {
                metaParcel.writeInt(metadata.size());
                for (int i = 0; i < metadata.size(); ++i) {
                    metaParcel.writeInt(metadata.keyAt(i));
                    metaParcel.writeByteArray(
                            ByteBuffer.allocate(4).order(ByteOrder.nativeOrder())
                                    .putInt(metadata.valueAt(i)).array());
                }
                metaParcel.setDataPosition(0);
            }
            nativeObject = nativeCreate(session, name, w, h, format, flags,
                    parent != null ? parent.mNativeObject : 0, metaParcel);
        } finally {
            metaParcel.recycle();
        }
        if (nativeObject == 0) {
            throw new OutOfResourcesException(
                    "Couldn't allocate SurfaceControl native object");
        }
        assignNativeObject(nativeObject, callsite);
    }

6. 第六步 刷新界面和更新焦点


            // We may be deferring layout passes at the moment, but since the client is interested
            // in the new out values right now we need to force a layout.
            mWindowPlacerLocked.performSurfacePlacement(true /* force */);

6.1 WindowSurfacePlacer#performSurfacePlacement 刷新界面和更新焦点

performSurfacePlacement 看方法名,perform surface place,即负责所有窗口的Surface的摆放工作,如何显示位置,大小等等,是WMS中的核心方法

90e8fa75df9f4c1bb4ed707d707d3fe1.jpg

下面这些流程的流程图如上

    final void performSurfacePlacement(boolean force) {
        if (mDeferDepth > 0 && !force) {
            mDeferredRequests++;
            return;
        }
//最大执行6次循环
        int loopCount = 6;
        do {
            mTraversalScheduled = false;
            performSurfacePlacementLoop();
            mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
            loopCount--;
        } while (mTraversalScheduled && loopCount > 0);
        mService.mRoot.mWallpaperActionPending = false;
    }

    private void performSurfacePlacementLoop() {
//此方法下面已经有地方将mInLayout置为true,说明已经正在执行performSurfacePlacementLoop方法了
        if (mInLayout) {
...
            return;
        }

        // TODO(multi-display):
        final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
//mWaitingForConfig作用是Used to gate application window layout until we have sent the complete configuration.
//当没有完成configuration change的时候,无需做relayout,直到configuration change完成
        if (defaultDisplay.mWaitingForConfig) {
            // Our configuration has changed (most likely rotation), but we
            // don't yet have the complete configuration to report to
            // applications.  Don't do any window layout until we have it.
            return;
        }
//屏幕没准备好,直接返回
        if (!mService.mDisplayReady) {
            // Not yet initialized, nothing to do.
            return;
        }
//对应第一行标志位,表示正在layout
        mInLayout = true;
//内存不足时,强制清理mForceRemoves集合,释放内存
        if (!mService.mForceRemoves.isEmpty()) {
            // Wait a little bit for things to settle down, and off we go.
            while (!mService.mForceRemoves.isEmpty()) {
                final WindowState ws = mService.mForceRemoves.remove(0);
                Slog.i(TAG, "Force removing: " + ws);
                ws.removeImmediately();
            }
            Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
            Object tmp = new Object();
            synchronized (tmp) {
                try {
                    tmp.wait(250);
                } catch (InterruptedException e) {
                }
            }
        }

        try {
//核心的一步
            mService.mRoot.performSurfacePlacement();
//标志位置为false,走完上面这步,layout就完成了
            mInLayout = false;

            if (mService.mRoot.isLayoutNeeded()) {
//需要layout,并且count<6
                if (++mLayoutRepeatCount < 6) {
                    requestTraversal();
                } else {
...
    }

6.2 RootWindowContainer#performSurfacePlacement

RootWindowContainer.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

    void performSurfacePlacement() {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
        try {
            performSurfacePlacementNoTrace();
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

 6.3 RootWindowContainer#performSurfacePlacementNoTrace - part1

这个方法也很长,当窗口的某些东西改变的时候,就会走到这里,由于太长,我们分开去讲

    void performSurfacePlacementNoTrace() {
        if (DEBUG_WINDOW_TRACE) {
//06-01 10:12:18.016  1890  2256 V WindowManager: performSurfacePlacementInner: entry. 
//Called by com.android.server.wm.RootWindowContainer.performSurfacePlacement:765 
//com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop:177 
//com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement:126 
            Slog.v(TAG, "performSurfacePlacementInner: entry. Called by "
                    + Debug.getCallers(3));
        }

        int i;

        if (mWmService.mFocusMayChange) {
            mWmService.mFocusMayChange = false;
//更新焦点窗口
            mWmService.updateFocusedWindowLocked(
                    UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
        }

        mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
        mUserActivityTimeout = -1;
        mObscureApplicationContentOnSecondaryDisplays = false;
        mSustainedPerformanceModeCurrent = false;
        mWmService.mTransactionSequence++;

        // TODO(multi-display): recents animation & wallpaper need support multi-display.
        final DisplayContent defaultDisplay = mWmService.getDefaultDisplayContentLocked();
//获取WindowSurfacePlacer,这个类专门用于摆放windows和他们的surfaces,
//全系统只有一个实例,在WMS实例化中进行的
        final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
//要开始进行过渡动画了
        if (SHOW_LIGHT_TRANSACTIONS) {
            Slog.i(TAG,
                    ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
        }
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
//设置surface参数,start a transaction,对一组 SurfaceControl 的原子更改。
//即通过SurfaceControl来通知native开始一个Transaction
        mWmService.openSurfaceTransaction();
        try {
//执行Transaction
//下面详细解释这里
            applySurfaceChangesTransaction();
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
        } finally {
//close surface Transaction
            mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
            if (SHOW_LIGHT_TRANSACTIONS) {
                Slog.i(TAG,
                        "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
            }
        }
...
剩下的分另一半说

6.3.1 RootWindowContainer#applySurfaceChangesTransaction

RootWindowContainer.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java

    private void applySurfaceChangesTransaction() {
        // TODO(multi-display): Support these features on secondary screens.
        final DisplayContent defaultDc = mDefaultDisplay;
        final DisplayInfo defaultInfo = defaultDc.getDisplayInfo();
        final int defaultDw = defaultInfo.logicalWidth;
        final int defaultDh = defaultInfo.logicalHeight;
        final SurfaceControl.Transaction t = defaultDc.getSyncTransaction();
...
//mChildren为“List of children for this window container”,
//也就是这个WindowContainer的一系列子windowContainer的集合
        final int count = mChildren.size();
//循环遍历
        for (int j = 0; j < count; ++j) {
//获取到这个WindowContainer对应的DisplayContent 
            final DisplayContent dc = mChildren.get(j);
//对这个DisplayContent进行applySurfaceChangesTransaction
            dc.applySurfaceChangesTransaction();
        }

        // Give the display manager a chance to adjust properties like display rotation if it needs
        // to.
        mWmService.mDisplayManagerInternal.performTraversal(t);
        if (t != defaultDc.mSyncTransaction) {
            SurfaceControl.mergeToGlobalTransaction(t);
        }
    }

借用一张图来表示mChildren,mChildren里保存的都是WidowContainer,并且这些WidowContainer按Z值排序,Z值越大越靠前

WindowContainer.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java "List of children for this window container. List is in z-order as the children appear on screen with the top-most window container at the tail of the list."

  protected final WindowList<E> mChildren = new WindowList<E>();

05342f3048dc4ea3adefed42dde7e65c.png

 

 6.3.2 DisplayContent#applySurfaceChangesTransaction

DisplayContent.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

    void applySurfaceChangesTransaction() {
        final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;

        beginHoldScreenUpdate();

        mTmpUpdateAllDrawn.clear();
...

        // Perform a layout, if needed.
        performLayout(true /* initial */, false /* updateInputWindows */);
        pendingLayoutChanges = 0;

        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");
        try {
            mDisplayPolicy.beginPostLayoutPolicyLw();
//遍历windows   执行mApplyPostLayoutPolicy
            forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
            mDisplayPolicy.finishPostLayoutPolicyLw();
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        mInsetsStateController.onPostLayout();

        mTmpApplySurfaceChangesTransactionState.reset();

        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyWindowSurfaceChanges");
        try {
//遍历windows
//执行mApplySurfaceChangesTransaction
            forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        prepareSurfaces();
...
        finishHoldScreenUpdate();
    }

 6.3.3 DisplayContent#performLayout

DisplayContent.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

    void performLayout(boolean initial, boolean updateInputWindows) {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performLayout");
        try {
            performLayoutNoTrace(initial, updateInputWindows);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
    }

    private void performLayoutNoTrace(boolean initial, boolean updateInputWindows) {
        if (!isLayoutNeeded()) {
            return;
        }
//将mLayoutNeeded = false;
//会打印堆栈:06-01 10:12:18.016  1890  2256 W WindowManager: clearLayoutNeeded: 
//callers=com.android.server.wm.DisplayContent.performLayoutNoTrace:5051 
//com.android.server.wm.DisplayContent.performLayout:5041 
//com.android.server.wm.DisplayContent.applySurfaceChangesTransaction:4963 
        clearLayoutNeeded();

        if (DEBUG_LAYOUT) {
//06-01 10:12:18.016  1890  2256 V WindowManager: performLayout: dw=3840 dh=7104 
            Slog.v(TAG, "-------------------------------------");
            Slog.v(TAG, "performLayout: dw=" + mDisplayInfo.logicalWidth
                    + " dh=" + mDisplayInfo.logicalHeight);
        }

        int seq = mLayoutSeq + 1;
        if (seq < 0) seq = 0;
        mLayoutSeq = seq;

        mTmpInitial = initial;

        // First perform layout of any root windows (not attached to another window).
//首先给所有windows执行layout,mPerformLayout稍后解释
        forAllWindows(mPerformLayout, true /* traverseTopToBottom */);

        // Now perform layout of attached windows, which usually depend on the position of the
        // window they are attached to. XXX does not deal with windows that are attached to windows
        // that are themselves attached.
//给所有attached windows执行layout操作
        forAllWindows(mPerformLayoutAttached, true /* traverseTopToBottom */);

        // Window frames may have changed. Tell the input dispatcher about it.
//更新input window
        mInputMonitor.setUpdateInputWindowsNeededLw();
        if (updateInputWindows) {
            mInputMonitor.updateInputWindowsLw(false /*force*/);
        }
    }

DisplayContent#  mPerformLayout赋值如下:

DisplayContent.java - OpenGrok cross reference for /frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

    private final Consumer<WindowState> mPerformLayout = w -> {
        if (w.mLayoutAttached) {
            return;
        }

        // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid
        // wasting time and funky changes while a window is animating away.
        final boolean gone = w.isGoneForLayout();

        if (DEBUG_LAYOUT) {
            Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame
                    + " config reported=" + w.isLastConfigReportedToClient());
            final ActivityRecord activity = w.mActivityRecord;
            if (gone) Slog.v(TAG, "  GONE: mViewVisibility=" + w.mViewVisibility
                    + " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible()
                    + " visibleRequested=" + (activity != null && activity.isVisibleRequested())
                    + " parentHidden=" + w.isParentWindowHidden());
            else Slog.v(TAG, "  VIS: mViewVisibility=" + w.mViewVisibility
                    + " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible()
                    + " visibleRequested=" + (activity != null && activity.isVisibleRequested())
                    + " parentHidden=" + w.isParentWindowHidden());
        }

        // If this view is GONE, then skip it -- keep the current frame, and let the caller know
        // so they can ignore it if they want.  (We do the normal layout for INVISIBLE windows,
        // since that means "perform layout as normal, just don't display").
        if (!gone || !w.mHaveFrame || w.mLayoutNeeded) {
            if (mTmpInitial) {
                w.resetContentChanged();
            }
            w.mSurfacePlacementNeeded = true;
            w.mLayoutNeeded = false;
            final boolean firstLayout = !w.isLaidOut();
// Called for each window attached to the window manager as layout is proceeding
//在布局进行时调用附加到窗口管理器的每个窗口
            getDisplayPolicy().layoutWindowLw(w, null, mDisplayFrames);
            w.mLayoutSeq = mLayoutSeq;

            // If this is the first layout, we need to initialize the last frames and inset values,
            // as otherwise we'd immediately cause an unnecessary resize.
            if (firstLayout) {
                // The client may compute its actual requested size according to the first layout,
                // so we still request the window to resize if the current frame is empty.
                if (!w.getFrame().isEmpty()) {
                    w.updateLastFrames();
                }
                w.onResizeHandled();
            }

            if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame=" + w.getFrame()
                    + " mParentFrame=" + w.getParentFrame()
                    + " mDisplayFrame=" + w.getDisplayFrame());
        }
    };

DisplayPolicy#layoutWindowLw

    public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
...
        mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
                win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
                win.getRequestedVisibleTypes(), win.mGlobalScale, sTmpClientFrames);

        win.setFrames(sTmpClientFrames, win.mRequestedWidth, win.mRequestedHeight);
  }
    

 大概log如下:

06-01 10:12:18.006  1890  2256 V WindowManager: Relayout Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: viewVisibility=0 req=7104x3840 {(0,0)(fillxfill) sim={adjust=resize forwardNavigation} ty=BASE_APPLICATION wanim=0x10302f2
06-01 10:12:18.006  1890  2256 V WindowManager:   fl=LAYOUT_IN_SCREEN LAYOUT_INSET_DECOR SPLIT_TOUCH HARDWARE_ACCELERATED DRAWS_SYSTEM_BAR_BACKGROUNDS
06-01 10:12:18.006  1890  2256 V WindowManager:   pfl=NO_MOVE_ANIMATION FORCE_DRAW_STATUS_BAR_BACKGROUND HIDE_NON_SYSTEM_OVERLAY_WINDOWS USE_BLAST FIT_INSETS_CONTROLLED
06-01 10:12:18.006  1890  2256 V WindowManager:   vsysui=LIGHT_STATUS_BAR LIGHT_NAVIGATION_BAR
06-01 10:12:18.006  1890  2256 V WindowManager:   apr=LIGHT_STATUS_BARS LIGHT_NAVIGATION_BARS
06-01 10:12:18.006  1890  2256 V WindowManager:   bhv=DEFAULT
06-01 10:12:18.006  1890  2256 V WindowManager:   fitSides=}
06-01 10:12:18.008  1890  2256 W WindowManager: setLayoutNeeded: callers=com.android.server.wm.WindowState.setDisplayLayoutNeeded:2671 com.android.server.wm.WindowManagerService.relayoutWindow:2419 com.android.server.wm.Session.relayout:249 
06-01 10:12:18.009  1890  2256 V WindowManager: Creating surface in session android.view.SurfaceSession@fcb7984 window WindowStateAnimator{31728a0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity} format=-1 flags=4
06-01 10:12:18.015  1890  2256 V WindowManager: Got surface: Surface(name=com.android.settings/com.android.settings.homepage.SettingsHomepageActivity)/@0xafd3c59, set left=0 top=0
06-01 10:12:18.015  1890  2256 I WindowManager: >>> OPEN TRANSACTION createSurfaceLocked
06-01 10:12:18.015  1890  2256 I WindowManager:   SURFACE CREATE pos=(0,0) HIDE: Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}
06-01 10:12:18.015  1890  2256 V WindowManager: Created surface WindowStateAnimator{31728a0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}
06-01 10:12:18.016  1890  2256 V WindowManager: performSurfacePlacementInner: entry. Called by com.android.server.wm.RootWindowContainer.performSurfacePlacement:765 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop:177 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement:126 
06-01 10:12:18.016  1890  2256 I WindowManager: >>> OPEN TRANSACTION performLayoutAndPlaceSurfaces
...
06-01 10:12:18.020  1890  2256 I WindowManager: <<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces
06-01 10:12:18.021  1890  2256 E WindowManager: performSurfacePlacementInner exit
06-01 10:12:18.021  1890  2256 V WindowManager: Already visible and does not turn on screen, skip preparing: Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}
06-01 10:12:18.022  1890  2256 W WindowManager: Moving IM target from null to null since mInputMethodWindow is null
06-01 10:12:18.022  1890  2256 V WindowManager: Win Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: isDrawn=false, animating=false
06-01 10:12:18.022  1890  2256 V WindowManager: Not displayed: s=Surface(name=com.android.settings/com.android.settings.homepage.SettingsHomepageActivity)/@0xafd3c59 pv=true mDrawState=1 ph=false th=true a=false
06-01 10:12:18.022  1890  2256 V WindowManager: Relayout complete Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: outFrames=ClientWindowFrames{frame=[0,0][7104,3840] display=[0,0][7104,3840] parentFrame=[0,0][0,0]}
06-01 10:12:18.214  1890  1950 I WindowManager: commitFinishDrawingLocked: Window{d8b1e28 u0 Splash Screen com.android.settings} cur mDrawState=HAS_DRAWN
06-01 10:12:18.214  1890  1950 D ActivityTaskManager: updateWindows: starting Window{d8b1e28 u0 Splash Screen com.android.settings} isOnScreen=true allDrawn=false freezingScreen=false
06-01 10:12:18.214  1890  1950 V WindowManager: Resizing Window{d8b1e28 u0 Splash Screen com.android.settings}: configChanged=false last=Rect(0, 0 - 7104, 3840) frame=Rect(0, 0 - 7104, 3840)
06-01 10:12:18.215  1890  1950 V WindowManager: performShow on Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: mDrawState=READY_TO_SHOW readyForDisplay=true starting=false during animation: policyVis=true parentHidden=false tok.visibleRequested=true tok.visible=true animating=false tok animating=false Callers=com.android.server.wm.WindowState.performShowLocked:4372 com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked:256 com.android.server.wm.DisplayContent.lambda$new$8:1082 com.android.server.wm.DisplayContent.$r8$lambda$NJwM1ysKPNyOazqyI2QXlp2I4yA:0 
...
06-01 10:12:18.220  1890  1950 V WindowManager: Win Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: isDrawn=true, animating=true

06-01 10:12:18.228  1890  1950 V WindowManager: Showing Window{8d0d088 u0 com.android.settings/com.android.settings.homepage.SettingsHomepageActivity}: mDrawState=READY_TO_SHOW readyForDisplay=true starting=false during animation: policyVis=true parentHidden=false tok.visibleRequested=true tok.visible=true animating=true tok animating=false Callers=com.android.server.wm.WindowState.performShowLocked:4387 com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked:256 com.android.server.wm.DisplayContent.lambda$new$8:1082 com.android.server.wm.DisplayContent.$r8$lambda$NJwM1ysKPNyOazqyI2QXlp2I4yA:0 

 

相关推荐

  1. Android14 WMS-Power键短按流程

    2024-06-06 14:16:07       6 阅读
  2. Android View绘制流程详解

    2024-06-06 14:16:07       34 阅读
  3. Android14 WMS-DisplayArea层级结构生成

    2024-06-06 14:16:07       31 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-06 14:16:07       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-06 14:16:07       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-06 14:16:07       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-06 14:16:07       18 阅读

热门阅读

  1. TOP10-k8s-安全措施

    2024-06-06 14:16:07       9 阅读
  2. Python语言句式:深度解析与高级应用

    2024-06-06 14:16:07       10 阅读
  3. Windows Docker手动迁移镜像

    2024-06-06 14:16:07       7 阅读
  4. 跨平台游戏引擎 Axmol-2.1.3 发布

    2024-06-06 14:16:07       6 阅读
  5. MySQL学习——触发器的语法和示例

    2024-06-06 14:16:07       8 阅读
  6. TS设置接收的形参类型

    2024-06-06 14:16:07       6 阅读
  7. 源代码防泄密--沙盒技术安全风险分析

    2024-06-06 14:16:07       9 阅读
  8. Nginx配置文件详解与实践

    2024-06-06 14:16:07       9 阅读
  9. 安全漏洞扫描工具

    2024-06-06 14:16:07       8 阅读
  10. 小游戏--跑酷

    2024-06-06 14:16:07       8 阅读