Android13 WindowManager updateViewLayout流程分析

WindowManager的updateViewLayout用于更新View的布局,updateViewLayout方法定义在WindowManager的父类接口ViewManager中,而实现addView方法的则是WindowManagerImpl中,如下所示:

//frameworks/base/core/java/android/view/WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyTokens(params);
        mGlobal.updateViewLayout(view, params);
    }
}

WindowManagerGlobal updateViewLayout

调用WindowManagerGlobal的updateViewLayout方法:

//frameworks/base/core/java/android/view/WindowManagerGlobal.java
public final class WindowManagerGlobal {
    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
 // 校验 LayoutParams 类型
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }


// 将 LayoutParams 添加到根 View 中
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;


        view.setLayoutParams(wparams);


        synchronized (mLock) {
     // 替换 View 相关的参数(添加 View 时将 View,ViewRootImpl,LayoutParams 添加到三个集合中)
            int index = findViewLocked(view, true); // 查询指定 View 在 mViews 集合中的位置。
            ViewRootImpl root = mRoots.get(index);
            mParams.remove(index);
            mParams.add(index, wparams);
     // 这里调用 ViewRootImpl.setLayoutParams 进行更新
            root.setLayoutParams(wparams, false);
        }
    }
}

上面方法主要处理如下:

1、调用WindowManagerGlobal的findViewLocked方法,查询指定 View 在 mViews 集合中的位置。

2、调用ViewRootImpl的setLayoutParams方法,设置视图的布局参数。

下面分别进行分析:

WindowManagerGlobal findViewLocked

调用WindowManagerGlobal的findViewLocked方法,查询指定 View 在 mViews 集合中的位置。

//frameworks/base/core/java/android/view/WindowManagerGlobal.java
public final class WindowManagerGlobal {
    private int findViewLocked(View view, boolean required) {
        final int index = mViews.indexOf(view);
        if (required && index < 0) {
            throw new IllegalArgumentException("View=" + view + " not attached to window manager");
        }
        return index;
    }
}

ViewRootImpl setLayoutParams

调用ViewRootImpl的setLayoutParams方法,设置视图的布局参数:

//frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
    public final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();
    public void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
        synchronized (this) {
            final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
            final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
            final int oldInsetRight = mWindowAttributes.surfaceInsets.right;
            final int oldInsetBottom = mWindowAttributes.surfaceInsets.bottom;
            final int oldSoftInputMode = mWindowAttributes.softInputMode;
            final boolean oldHasManualSurfaceInsets = mWindowAttributes.hasManualSurfaceInsets;


            if (DEBUG_KEEP_SCREEN_ON && (mClientWindowLayoutFlags
                    & WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) != 0
                    && (attrs.flags&WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) == 0) {
                Slog.d(mTag, "setLayoutParams: FLAG_KEEP_SCREEN_ON from true to false!");
            }


            // Keep track of the actual window flags supplied by the client.
            mClientWindowLayoutFlags = attrs.flags;


            // Preserve compatible window flag if exists.
            final int compatibleWindowFlag = mWindowAttributes.privateFlags
                    & WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;


            // Preserve system UI visibility.
            final int systemUiVisibility = mWindowAttributes.systemUiVisibility;
            final int subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;


            // Preserve appearance and behavior.
            final int appearance = mWindowAttributes.insetsFlags.appearance;
            final int behavior = mWindowAttributes.insetsFlags.behavior;
            final int appearanceAndBehaviorPrivateFlags = mWindowAttributes.privateFlags
                    & (PRIVATE_FLAG_APPEARANCE_CONTROLLED | PRIVATE_FLAG_BEHAVIOR_CONTROLLED);


            final int changes = mWindowAttributes.copyFrom(attrs);
            if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
                // Recompute system ui visibility.
                mAttachInfo.mRecomputeGlobalAttributes = true;
            }
            if ((changes & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
                // Request to update light center.
                mAttachInfo.mNeedsUpdateLightCenter = true;
            }
            if (mWindowAttributes.packageName == null) {
                mWindowAttributes.packageName = mBasePackageName;
            }


            // Restore preserved flags.
            mWindowAttributes.systemUiVisibility = systemUiVisibility;
            mWindowAttributes.subtreeSystemUiVisibility = subtreeSystemUiVisibility;
            mWindowAttributes.insetsFlags.appearance = appearance;
            mWindowAttributes.insetsFlags.behavior = behavior;
            mWindowAttributes.privateFlags |= compatibleWindowFlag
                    | appearanceAndBehaviorPrivateFlags
                    | WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;


            if (mWindowAttributes.preservePreviousSurfaceInsets) {
                // Restore old surface insets.
                mWindowAttributes.surfaceInsets.set(
                        oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
                mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
            } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft
                    || mWindowAttributes.surfaceInsets.top != oldInsetTop
                    || mWindowAttributes.surfaceInsets.right != oldInsetRight
                    || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) {
                mNeedsRendererSetup = true;
            }


            applyKeepScreenOnFlag(mWindowAttributes);


            if (newView) {
                mSoftInputMode = attrs.softInputMode;
                requestLayout(); //请求重新布局视图树
            }


            // Don't lose the mode we last auto-computed.
            if ((attrs.softInputMode & SOFT_INPUT_MASK_ADJUST)
                    == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
                mWindowAttributes.softInputMode = (mWindowAttributes.softInputMode
                        & ~SOFT_INPUT_MASK_ADJUST) | (oldSoftInputMode & SOFT_INPUT_MASK_ADJUST);
            }


            if (mWindowAttributes.softInputMode != oldSoftInputMode) {
                requestFitSystemWindows();
            }


            mWindowAttributesChanged = true;
            scheduleTraversals(); //调度视图的遍历和绘制过程
        }
    }
}

上面方法主要处理如下:

1、调用ViewRootImpl的requestLayout方法,请求重新布局视图树。

2、调用ViewRootImpl的scheduleTraversals方法,调度视图的遍历和绘制过程。

下面分别进行分析:

ViewRootImpl requestLayout

 调用ViewRootImpl的requestLayout方法,请求重新布局:

//frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread(); //校验所在线程
            mLayoutRequested = true;
            scheduleTraversals();  //调度视图的遍历和绘制过程
        }
    }
}

调用ViewRootImpl的scheduleTraversals方法,调度视图的遍历和绘制过程:

/frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {


    public boolean mTraversalScheduled;
    final Choreographer mChoreographer;


    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }


    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier(); //发送一个同步屏障,以确保后续的同步消息在视图绘制完成之前不会执行
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); //下一帧绘制之前执行mTraversalRunnable
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
}

上面方法主要处理如下:

1、调用Choreographer的postCallback方法,在下一帧绘制之前执行mTraversalRunnable。

2、调用ViewRootImpl的pokeDrawLockIfNeeded方法,请求绘制锁定。

下面分别进行分析:

Choreographer postCallback

调用Choreographer的postCallback方法,用于将一个任务添加到Choreographer的任务队列中,以便在下一帧绘制之前执行。

传入的mTraversalRunnable为TraversalRunnable类,在下一帧绘制前调用TraversalRunnable的run方法,在run方法中调用doTraversal方法:

//frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
    private boolean mProfile = false;
    final ViewRootHandler mHandler = new ViewRootHandler();
    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);


            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }


            performTraversals();


            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }
}
ViewRootImpl performTraversals

调用ViewRootImpl的performTraversals方法,执行View的三大流程(measure、layout、draw):

Android13 ViewRootImpl performTraversals流程分析-CSDN博客

ViewRootImpl pokeDrawLockIfNeeded

调用ViewRootImpl的pokeDrawLockIfNeeded方法:

//frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
    final IWindowSession mWindowSession;
    void pokeDrawLockIfNeeded() {
        if (!Display.isDozeState(mAttachInfo.mDisplayState)) {
            // Only need to acquire wake lock for DOZE state.
            return;
        }
        if (mWindowAttributes.type != WindowManager.LayoutParams.TYPE_BASE_APPLICATION) {
            // Non-activity windows should be responsible to hold wake lock by themself, because
            // usually they are system windows.
            return;
        }
        if (mAdded && mTraversalScheduled && mAttachInfo.mHasWindowFocus) {
            try {
                mWindowSession.pokeDrawLock(mWindow);
            } catch (RemoteException ex) {
                // System server died, oh well.
            }
        }
    }
}

调用mWindowSession(IWindowSession)的pokeDrawLock方法,IWindowSession是一个接口,由Session实现:

//frameworks/base/services/core/java/com/android/server/wm/Session.java
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
    final WindowManagerService mService;
    public void pokeDrawLock(IBinder window) {
        final long identity = Binder.clearCallingIdentity();
        try {
            mService.pokeDrawLock(this, window);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }
}

调用WindowManagerService的pokeDrawLock方法,请求绘制锁定:

//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public class WindowManagerService extends IWindowManager.Stub
        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
    public void pokeDrawLock(Session session, IBinder token) {
        synchronized (mGlobalLock) {
            WindowState window = windowForClientLocked(session, token, false);
            if (window != null) {
                window.pokeDrawLockLw(mDrawLockTimeoutMillis);
            }
        }
    }
}
ViewRootImpl scheduleTraversals

调用ViewRootImpl的scheduleTraversals方法,调度视图的遍历和绘制过程,与上面流程一致。

  • 21
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值