WindowManagerService 核心函数relayout(6)
简述
WMS中最重要的一个方法就是这个relayout,当窗口的树结构、大小等发生变化,就会通过这个方法重新计算所有窗口的位置,大小等属性。其中还包括对Insets的计算等等。
这个方法触发的路径很多,app UI变化binder调用触发,窗口动画触发,WMS窗口的一些属性变化,Insets变化等等都会调用这个方法来重新对所有的窗口进行计算。
窗口的几个绘制状态
WindowState持有一个WindowStateAnimator,其中有一个变量mDrawState,表示窗口当前的状态。它有如下的一些状态,我们常常可以用这个状态来排查问题。
// 这个WindowState刚刚新建,还没有构建Surface时就是这个状态,一般是在addWindow创建WindowState但是还没relayoutWindow之前。
static final int NO_SURFACE = 0;
// 构建Surface完成,一般是在addWindow之后首次调用relayoutWindow,会构建Surface。
static final int DRAW_PENDING = 1;
// app 在performTraversals时候会执行onMeasure,onLayout,onDraw,当Draw完成之后会调用reportDrawFinished,binder到WMS侧调用对应窗口WindowState.finishDrawing
// 当排查某些黑屏问题时,如果发现窗口已经处于COMMIT_DRAW_PENDING或者以后的状态,则说明app侧的渲染已经完成,不是卡在app侧(当然还有可能app就是渲染了一个黑屏)
static final int COMMIT_DRAW_PENDING = 2;
// 在上面app调用WMS binder流程,后面会通过requestTraversal请求窗口刷新,流程中会将所有COMMIT_DRAW_PENDING状态改成READY_TO_SHOW,表示这个窗口随时可以显示
static final int READY_TO_SHOW = 3;
// 等到该token的所有Window都可以显示的时候,就会把他们状态改成HAS_DRAWN,表示窗口已经显示
static final int HAS_DRAWN = 4;
流程图:
app侧
我们在SurfaceFlinger章节提到过app是怎么请求下一个VSync,然后一直到ViewRootImpl.doTraversal方法,在添加窗口流程中ViewRootImpl.setView方法里也调用了requestLayout,里面会调用scheduleTraversals去请求下一个VSync信号,然后执行到ViewRootImpl.doTraversal,所以我们就从这个方法开始看。
1.1 ViewRootImpl.doTraversal
主要就是通过调用performTraversals来重新渲染页面
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
//...
// 调用了performTraversals,详见1.2
performTraversals();
// ...
}
}
1.2 ViewRootImpl.performTraversals
这个方法非常长,我们只看我们关心的内容。
这个方法最主要的逻辑是根据是否需要重新布局,如果需要则调用relayoutWindow通知WMS来重新计算窗口大小,此外还会根据属性变化判断是否需要重新onMeasure,onLayout,onDraw
此外还需要关注一个点,这里会通过SurfaceSyncGroup来对app侧的渲染进行同步,比如app如果有SurfaceView,他的渲染可能不是和其他View同步的,这时候就会通过该类来进行同步,除此之外,我们通过GPU硬件渲染时,不会阻塞等待GPU渲染完成,而是通过fence的回调,这一点在SurfaceFlinger章节有详细介绍过,方法createSyncIfNeeded构建了SurfaceSyncGroup,同时会注册回调,当渲染完成时就会调用回调,回调主要调用了reportDrawFinished来通知WMS这个窗口渲染完成,WMS侧会将对应窗口状态改为COMMIT_DRAW_PENDING。
private void performTraversals() {
// ...
boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
if (layoutRequested) {
// ...
// 如果需要重新布局,则需要预先计算窗口大小
// 这里主要目的是计算窗口大小,如果窗口大小不依赖于子View,这里不会调用performMeasure,而是设置mViewMeasureDeferred为true,在后面去调用performMeasure
windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(),
desiredWindowWidth, desiredWindowHeight, shouldOptimizeMeasure);
}
// ...
// 详见1.3
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
// ... 更新渲染线程中的Surface
// ...
// 更新渲染线程对象的一些属性
final ThreadedRenderer threadedRenderer = mAttachInfo.mThreadedRenderer;
if (threadedRenderer != null && threadedRenderer.isEnabled()) {
if (hwInitialized
|| mWidth != threadedRenderer.getWidth()
|| mHeight != threadedRenderer.getHeight()
|| mNeedsRendererSetup) {
threadedRenderer.setup(mWidth, mHeight, mAttachInfo,
mWindowAttributes.surfaceInsets);
mNeedsRendererSetup = false;
}
}
if (!mStopped || mReportNextDraw) {
if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
|| dispatchApplyInsets || updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
lp.privateFlags);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height,
lp.privateFlags);
// 执行onMeasure
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
int width = host.getMeasuredWidth();
int height = host.getMeasuredHeight();
boolean measureAgain = false;
// 如果有权重相关的配置,需要再measure一次
if (lp.horizontalWeight > 0.0f) {
width += (int) ((mWidth - width) * lp.horizontalWeight);
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
MeasureSpec.EXACTLY);
measureAgain = true;
}
if (lp.verticalWeight > 0.0f) {
height += (int) ((mHeight - height) * lp.verticalWeight);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
MeasureSpec.EXACTLY);
measureAgain = true;
}
// 第二次onMeasure
if (measureAgain) {
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}
layoutRequested = true;
}
}
} else {
maybeHandleWindowMove(frame);
}
// 如果前面没有测量,这里就会测量一次
if (mViewMeasureDeferred) {
performMeasure(
MeasureSpec.makeMeasureSpec(frame.width(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(frame.height(), MeasureSpec.EXACTLY));
}
if (surfaceSizeChanged || surfaceReplaced || surfaceCreated ||
windowAttributesChanged || mChildBoundingInsetsChanged) {
// apply mTransaction,将前面对窗口大小的变化等同步到SurfaceFlinger
// 这里是为了处理一些极端case才把apply的事情放在app侧而不是WMS侧
prepareSurfaces();
mChildBoundingInsetsChanged = false;
}
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
if (didLayout) {
// 这里是执行onLayout的地方
performLayout(lp, mWidth, mHeight);
// ...
}
if (!cancelAndRedraw) {
// ...
// 这里注册了SurfaceSyncGroup ready状态的回调,主要是向WMS触发reportDrawFinished,通知WMS当前窗口渲染完成。(通知窗口进入COMMIT_DRAW_PENDING状态)
createSyncIfNeeded();
// ...
}
if (!isViewVisible) {
// ... 不可见则做一些清理操作
} else if (cancelAndRedraw) {
// ...
// 需要redraw,重新触发下一个Vsync
scheduleTraversals();
} else {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
}
mPendingTransitions.clear();
}
// 调用performDraw,会执行View onDraw渲染
// 当View为空或者灭屏情况performDraw返回false,这时候直接触发mActiveSurfaceSyncGroup的ready
if (!performDraw() && mActiveSurfaceSyncGroup != null) {
mActiveSurfaceSyncGroup.markSyncReady();
}
}
// ...
}
1.3 relayoutWindow
这里调用了mWindowLayout.computeFrames对窗口大小和位置进行计算。且还会调用relayout binder到WMS去做窗口重新Layout。
后面我们会看到在WMS中窗口Layout的时候,还会用computeFrames去计算窗口的大小位置
这里其实是一个优化,如果窗口没有位置尺寸变化,会走relayoutAsync,这样WMS计算后不需要把结果返回给clinet,可以优化一次binder通信。
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
final WindowConfiguration winConfigFromAm = getConfiguration().windowConfiguration;
final WindowConfiguration winConfigFromWm =
mLastReportedMergedConfiguration.getGlobalConfiguration().windowConfiguration;
final WindowConfiguration winConfig = getCompatWindowConfiguration();
final int measuredWidth = mMeasuredWidth;
final int measuredHeight = mMeasuredHeight;
final boolean relayoutAsync;
if (LOCAL_LAYOUT
&& (mViewFrameInfo.flags & FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED) == 0
&& mWindowAttributes.type != TYPE_APPLICATION_STARTING
&& mSyncSeqId <= mLastSyncSeqId
&& winConfigFromAm.diff(winConfigFromWm, false /* compareUndefined */) == 0) {
final InsetsState state = mInsetsController.getState();
final Rect displayCutoutSafe = mTempRect;
state.getDisplayCutoutSafe(displayCutoutSafe);
// 计算窗口大小,通过mTmpFrames返回,详见1.3.1
mWindowLayout.computeFrames(mWindowAttributes.forRotation(winConfig.getRotation()),
state, displayCutoutSafe, winConfig.getBounds(), winConfig.getWindowingMode(),
measuredWidth, measuredHeight, mInsetsController.getRequestedVisibleTypes(),
1f /* compatScale */, mTmpFrames);
mWinFrameInScreen.set(mTmpFrames.frame);
if (mTranslator != null) {
mTranslator.translateRectInAppWindowToScreen(mWinFrameInScreen);
}
// 如果窗口位置和大小同时发生变化,我们还是要触发relayout,为了获取一个syncSeqId,需要触发BLAST同步。
// 否则我们就只需要触发relayoutAsync,这两者的区别就是是否会通过WMS返回窗口的大小等信息。一般只需要app本地计算窗口大小即可。
final Rect oldFrame = mLastLayoutFrame;
final Rect newFrame = mTmpFrames.frame;
final boolean positionChanged =
newFrame.top != oldFrame.top || newFrame.left != oldFrame.left;
final boolean sizeChanged =
newFrame.width() != oldFrame.width() || newFrame.height() != oldFrame.height();
relayoutAsync = !positionChanged || !sizeChanged;
} else {
relayoutAsync = false;
}
// ...
final int requestedWidth = (int) (measuredWidth * appScale + 0.5f);
final int requestedHeight = (int) (measuredHeight * appScale + 0.5f);
int relayoutResult = 0;
mRelayoutSeq++;
// relayoutAsync最终还是调用的relayout,只不过会将out相关的参数都传null,所以我们直接看relayout,详见1.4
if (relayoutAsync) {
mWindowSession.relayoutAsync(mWindow, params,
requestedWidth, requestedHeight, viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
mLastSyncSeqId);
} else {
relayoutResult = mWindowSession.relayout(mWindow, params,
requestedWidth, requestedHeight, viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mRelayoutSeq,
mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
mTempInsets, mTempControls, mRelayoutBundle);
mRelayoutRequested = true;
final int maybeSyncSeqId = mRelayoutBundle.getInt("seqid");
if (maybeSyncSeqId > 0) {
mSyncSeqId = maybeSyncSeqId;
}
mWinFrameInScreen.set(mTmpFrames.frame);
// ...兼容模式对窗口大小等处理
// 触发Insets更新回调,这里方法的流程上一节介绍过了
mInsetsController.onStateChanged(mTempInsets);
mInsetsController.onControlsChanged(mTempControls.get());
mPendingAlwaysConsumeSystemBars =
(relayoutResult & RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS) != 0;
}
// ...
if (mSurfaceControl.isValid()) {
// Android12之后都会使用BLAST,Blast相关的信息在SurfaceFlinger章节介绍过了
if (!useBLAST()) {
mSurface.copyFrom(mSurfaceControl);
} else {
// 如果窗口等大小有所变化,需要修改BlastBufferQueue,就在这里触发
updateBlastSurfaceIfNeeded();
}
if (mAttachInfo.mThreadedRenderer != null) {
// 将新的SurfaceControl和mBlastBufferQueue同步给渲染线程。
mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
}
updateRenderHdrSdrRatio();
if (mPreviousTransformHint != transformHint) {
mPreviousTransformHint = transformHint;
dispatchTransformHintChanged(transformHint);
}
} else {
if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.pause()) {
mDirty.set(0, 0, mWidth, mHeight);
}
destroySurface();
}
// 将计算返回的窗口大小配置到mWinFrame中
setFrame(mTmpFrames.frame, true /* withinRelayout */);
return relayoutResult;
}
1.3.1 WindowLayout.computeFrames
计算窗口大小和位置,输出会存储在ClientWindowFrames里,ClientWindowFrames有四个主要的变量,attachedFrame、displayFrame、parentFrame、frame。
attachedFrame一般是父窗口大小,displayFrame是屏幕大小除去Insets,parentFrame是父窗口,MATCH_PARENT和gravity需要参考的大小,frame事窗口自身的大小。
public void computeFrames(WindowManager.LayoutParams attrs, InsetsState state,
Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
int requestedWidth, int requestedHeight, @InsetsType int requestedVisibleTypes,
float compatScale, ClientWindowFrames frames) {
final int type = attrs.type;
final int fl = attrs.flags;
final int pfl = attrs.privateFlags;
final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
// 下面几个是ClientWindowFrames里面的变量,用来存放不同的结果
// 如果不为空,一般是父窗口大小
final Rect attachedWindowFrame = frames.attachedFrame;
// 一般是屏幕大小除去Insets
final Rect outDisplayFrame = frames.displayFrame;
// MATCH_PARENT和gravity需要参考的大小
final Rect outParentFrame = frames.parentFrame;
// 窗口自身实际大小
final Rect outFrame = frames.frame;
// 上一章有提过InsetsState会记录所有Insets信息,这里计算所有Insets的bounds
final Insets insets = state.calculateInsets(windowBounds, attrs.getFitInsetsTypes(),
attrs.isFitInsetsIgnoringVisibility());
final @WindowInsets.Side.InsetsSide int sides = attrs.getFitInsetsSides();
final int left = (sides & WindowInsets.Side.LEFT) != 0 ? insets.left : 0;
final int top = (sides & WindowInsets.Side.TOP) != 0 ? insets.top : 0;
final int right = (sides & WindowInsets.Side.RIGHT) != 0 ? insets.right : 0;
final int bottom = (sides & WindowInsets.Side.BOTTOM) != 0 ? insets.bottom : 0;
// 将windowBounds间去 Insets区域作为outDisplayFrame输出区域
outDisplayFrame.set(windowBounds.left + left, windowBounds.top + top,
windowBounds.right - right, windowBounds.bottom - bottom);
// 如果attachedWindowFrame为空,则没有父窗口,参考大小就设置为outDisplayFrame,还需要处理输入法Insets
if (attachedWindowFrame == null) {
outParentFrame.set(outDisplayFrame);
if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) {
final InsetsSource source = state.peekSource(ID_IME);
if (source != null) {
outParentFrame.inset(source.calculateInsets(
outParentFrame, false /* ignoreVisibility */));
}
}
} else {
// layoutInScreen表示窗口全屏显示
outParentFrame.set(!layoutInScreen ? attachedWindowFrame : outDisplayFrame);
}
// Compute bounds restricted by display cutout
final int cutoutMode = attrs.layoutInDisplayCutoutMode;
final DisplayCutout cutout = state.getDisplayCutout();
final Rect displayCutoutSafeExceptMaybeBars = mTempDisplayCutoutSafeExceptMaybeBarsRect;
displayCutoutSafeExceptMaybeBars.set(displayCutoutSafe);
frames.isParentFrameClippedByDisplayCutout = false;
if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS && !cutout.isEmpty()) {
// ... 刘海屏的一些计算
}
final boolean noLimits = (attrs.flags & FLAG_LAYOUT_NO_LIMITS) != 0;
final boolean inMultiWindowMode = WindowConfiguration.inMultiWindowMode(windowingMode);
// 如果带FLAG_LAYOUT_NO_LIMITS,outDisplayFrame设置无边界
if (noLimits && type != TYPE_SYSTEM_ERROR && !inMultiWindowMode) {
outDisplayFrame.left = MIN_X;
outDisplayFrame.top = MIN_Y;
outDisplayFrame.right = MAX_X;
outDisplayFrame.bottom = MAX_Y;
}
final boolean hasCompatScale = compatScale != 1f;
final int pw = outParentFrame.width();
final int ph = outParentFrame.height();
final boolean extendedByCutout =
(attrs.privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0;
int rw = requestedWidth;
int rh = requestedHeight;
float x, y;
int w, h;
// 如果requested宽高为UNSPECIFIED_LENGTH,设置为attrs的宽高,如果attrs的宽高为0,设置成outParentFrame的边界。
if (rw == UNSPECIFIED_LENGTH || extendedByCutout) {
rw = attrs.width >= 0 ? attrs.width : pw;
}
if (rh == UNSPECIFIED_LENGTH || extendedByCutout) {
rh = attrs.height >= 0 ? attrs.height : ph;
}
// 根据attrs里属性计算宽高,缩放。
if ((attrs.flags & FLAG_SCALED) != 0) {
if (attrs.width < 0) {
w = pw;
} else if (hasCompatScale) {
w = (int) (attrs.width * compatScale + .5f);
} else {
w = attrs.width;
}
if (attrs.height < 0) {
h = ph;
} else if (hasCompatScale) {
h = (int) (attrs.height * compatScale + .5f);
} else {
h = attrs.height;
}
} else {
if (attrs.width == MATCH_PARENT) {
w = pw;
} else if (hasCompatScale) {
w = (int) (rw * compatScale + .5f);
} else {
w = rw;
}
if (attrs.height == MATCH_PARENT) {
h = ph;
} else if (hasCompatScale) {
h = (int) (rh * compatScale + .5f);
} else {
h = rh;
}
}
// 计算缩放position
if (hasCompatScale) {
x = attrs.x * compatScale;
y = attrs.y * compatScale;
} else {
x = attrs.x;
y = attrs.y;
}
if (inMultiWindowMode
&& (attrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) == 0) {
w = Math.min(w, pw);
h = Math.min(h, ph);
}
final boolean fitToDisplay = !inMultiWindowMode
|| ((attrs.type != TYPE_BASE_APPLICATION) && !noLimits);
// 根据gravity计算位置,输出到outFrame
Gravity.apply(attrs.gravity, w, h, outParentFrame,
(int) (x + attrs.horizontalMargin * pw),
(int) (y + attrs.verticalMargin * ph), outFrame);
// 将屏幕大小作为父布局,适配Gravity
if (fitToDisplay) {
Gravity.applyDisplay(attrs.gravity, outDisplayFrame, outFrame);
}
if (extendedByCutout) {
extendFrameByCutout(displayCutoutSafe, outDisplayFrame, outFrame,
mTempRect);
}
}
1.4 WindowManagerService.relayoutWindow
中间的调用基本没有什么额外逻辑,我们直接到WindowManagerService到relayoutWindow这里。
这里有一些type和attrs的处理,大多数都写了注释,感兴趣可以自己研究一下,我们主要关注最重要的两个方法createSurfaceControl和mWindowPlacerLocked.performSurfacePlacement(true)
前者是用来创建SurfaceControl的,我们前面在添加窗口的流程中提过,窗口添加完成后WindowState并没有立刻创建SurfaceControl,而是在这里创建的,详见1.4.1。
后者就是WMS非常核心的方法,用于对所有窗口进行重新布局计算的,详见1.5。
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) {
// ... 一些变量初始化
synchronized (mGlobalLock) {
// 根据调用者参数找到对应的窗口
final WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
return 0;
}
// 这个序列可以保证binder的先后,如果序列号更小这里直接return丢弃了。
if (win.mRelayoutSeq < seq) {
win.mRelayoutSeq = seq;
} else if (win.mRelayoutSeq > seq) {
return 0;
}
// ...
final DisplayContent displayContent = win.getDisplayContent();
final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
// 每个WindowState都有一个WindowStateAnimator,主要处理窗口的Surface和动画相关的逻辑
WindowStateAnimator winAnimator = win.mWinAnimator;
if (viewVisibility != View.GONE) {
win.setRequestedSize(requestedWidth, requestedHeight);
}
int attrChanges = 0;
int flagChanges = 0;
int privateFlagChanges = 0;
if (attrs != null) {
// 根据窗口type做一些参数调整,如Toast类型不能Touch等。
displayPolicy.adjustWindowParamsLw(win, attrs);
// 如果flag带FLAG_SLIPPERY,需要检查权限。(滑动触摸,例如两个并列窗口,从A滑到B事件不会断)
attrs.flags = sanitizeFlagSlippery(attrs.flags, win.getName(), uid, pid);
// 对INPUT_FEATURE_SPY,检测权限。(一般用于一些全局手势拦截对窗口)
attrs.inputFeatures = sanitizeSpyWindow(attrs.inputFeatures, win.getName(), uid,
pid);
int disableFlags =
(attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility) & DISABLE_MASK;
if (disableFlags != 0 && !hasStatusBarPermission(pid, uid)) {
disableFlags = 0;
}
win.mDisableFlags = disableFlags;
// ... 检验type是否变化,已经add窗口不能改变type
// 检测attrs里面InsetsProvider是否变化,已经add对窗口也不能改变InsetsProvider(InsetsProvider在Insets介绍时候提到过)
if (!(win.mAttrs.providedInsets == null && attrs.providedInsets == null)) {
// ...
}
flagChanges = win.mAttrs.flags ^ attrs.flags;
privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags;
// 对比attrs对变化。
attrChanges = win.mAttrs.copyFrom(attrs);
final boolean layoutChanged =
(attrChanges & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0;
// 不同的变化需要做不同的操作
// systemui变化需要重新布局
if (layoutChanged || (attrChanges
& WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED) != 0) {
win.mLayoutNeeded = true;
}
// 如果窗口有提供屏幕相关的Insets,并且变化了,需要计算屏幕的Insets是否变化,如果变化了要通知config变化,需要通知其他应用
if (layoutChanged && win.providesDisplayDecorInsets()) {
configChanged = displayPolicy.updateDecorInsetsInfo();
}
// FLAG_DISMISS_KEYGUARD是去除锁屏界面,FLAG_SHOW_WHEN_LOCKED表示窗口能在锁屏时显示
if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0
|| (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) {
win.mActivityRecord.checkKeyguardFlagsChanged();
}
// SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS 表示隐藏非系统的悬浮窗
if ((privateFlagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
updateNonSystemOverlayWindowsVisibilityIfNeeded(
win, win.mWinAnimator.getShown());
}
// PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC表示窗口和颜色空间无关,可以使用任意的颜色空间。(颜色空间应该就是指颜色的编码方式)
if ((attrChanges & (WindowManager.LayoutParams.PRIVATE_FLAGS_CHANGED)) != 0) {
winAnimator.setColorSpaceAgnosticLocked((win.mAttrs.privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
}
// 这里是一些屏幕策略,判断窗口变化后关联的Activity是否还可以保留在当前屏幕上。
if (displayContent.mDwpcHelper.hasController()
&& win.mActivityRecord != null && (!win.mRelayoutCalled || flagChanges != 0
|| privateFlagChanges != 0)) {
// ...
}
}
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;
// 如果窗口是从不可见-》可见,可能会影响输入法(输入焦点变化)
final boolean becameVisible =
(oldVisibility == View.INVISIBLE || oldVisibility == View.GONE)
&& viewVisibility == View.VISIBLE;
boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0
|| becameVisible;
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;
win.setViewVisibility(viewVisibility);
win.setDisplayLayoutNeeded();
win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
// 只有当可见窗口变化/是一个starting window/关联的Activity可见时,我们才触发relayout
final boolean shouldRelayout = viewVisibility == View.VISIBLE &&
(win.mActivityRecord == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
|| win.mActivityRecord.isClientVisible());
// 如果当前没有正在执行退出动画,需要判断是否需要启动一个。
if (!shouldRelayout && winAnimator.hasSurface() && !win.mAnimatingExit) {
result |= RELAYOUT_RES_SURFACE_CHANGED;
if (wallpaperMayMove) {
displayContent.mWallpaperController.adjustWallpaperWindows();
}
tryStartExitingAnimation(win, winAnimator);
}
// 创建SurfaceControl
if (shouldRelayout && outSurfaceControl != null) {
try {
// 详见1.4.1
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
} catch (Exception e) {
displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
return 0;
}
}
// 触发一次layout,这里是布局的核心逻辑,详见1.5
mWindowPlacerLocked.performSurfacePlacement(true /* force */);
if (shouldRelayout) {
//
result = win.relayoutVisibleWindow(result);
if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
focusMayChange = true;
}
if (win.mAttrs.type == TYPE_INPUT_METHOD
&& displayContent.mInputMethodWindow == null) {
displayContent.setInputMethodWindowLocked(win);
imMayMove = true;
}
win.adjustStartingWindowFlags();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} else {
winAnimator.mEnterAnimationPending = false;
winAnimator.mEnteringAnimation = false;
if (outSurfaceControl != null) {
if (viewVisibility == View.VISIBLE && winAnimator.hasSurface()) {
// 如果已经通知client不可见,但是客户端未处理或者还需要画最后一帧,如果已经有Surface还是让client使用,但是不会创建新的Surface
winAnimator.mSurfaceController.getSurfaceControl(outSurfaceControl);
} else {
try {
// 客户端已经知道窗口不可见,释放Surface
outSurfaceControl.release();
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
//... 处理焦点变化
if (wallpaperMayMove) {
displayContent.pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
if (win.mActivityRecord != null) {
displayContent.mUnknownAppVisibilityController.notifyRelayouted(win.mActivityRecord);
}
configChanged |= displayContent.updateOrientation();
if (toBeDisplayed && win.mIsWallpaper) {
displayContent.mWallpaperController.updateWallpaperOffset(win, false /* sync */);
}
if (win.mActivityRecord != null) {
win.mActivityRecord.updateReportedVisibilityLocked();
}
if (displayPolicy.areSystemBarsForcedConsumedLw()) {
result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
}
if (!win.isGoneForLayout()) {
win.mResizedWhileGone = false;
}
if (outFrames != null && outMergedConfiguration != null) {
// 填充Frame和Configuration用于返回给app
win.fillClientWindowFramesAndConfiguration(outFrames, outMergedConfiguration,
false /* useLatestConfig */, shouldRelayout);
win.onResizeHandled();
}
if (outInsetsState != null) {
outInsetsState.set(win.getCompatInsetsState(), true /* copySources */);
}
win.mInRelayout = false;
final boolean winVisibleChanged = win.isVisible() != wasVisible;
if (win.isImeOverlayLayeringTarget() && winVisibleChanged) {
dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), win.mAttrs.type,
win.isVisible(), false /* removed */);
}
// 通知输入法输入焦点窗口变化。
final boolean isImeInputTarget = win.getDisplayContent().getImeInputTarget() == win;
if (isImeInputTarget && winVisibleChanged) {
dispatchImeInputTargetVisibilityChanged(win.mClient.asBinder(),
win.isVisible() /* visible */, false /* removed */);
}
if (outSyncIdBundle != null) {
final int maybeSyncSeqId;
if (USE_BLAST_SYNC && win.useBLASTSync() && viewVisibility == View.VISIBLE
&& win.mSyncSeqId > lastSyncSeqId) {
maybeSyncSeqId = win.shouldSyncWithBuffers() ? win.mSyncSeqId : -1;
win.markRedrawForSyncReported();
} else {
maybeSyncSeqId = -1;
}
outSyncIdBundle.putInt("seqid", maybeSyncSeqId);
}
if (configChanged) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"relayoutWindow: postNewConfigurationToHandler");
// 通知Configuration更新,这里会通知到各个应用。
displayContent.sendNewConfiguration();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
if (outActiveControls != null) {
getInsetsSourceControls(win, outActiveControls);
}
}
Binder.restoreCallingIdentity(origId);
return result;
}
1.4.1 WindowManagerService.createSurfaceControl
主要调用了WindowStateAnimator.createSurfaceLocked来创建WindowSurfaceController,WindowSurfaceController的构造函数里面会创建一个SurfaceControl
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");
// 调用WindowStateAnimator.createSurfaceLocked来创建WindowSurfaceController,详见1.4.2
surfaceController = winAnimator.createSurfaceLocked();
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
if (surfaceController != null) {
// 将SurfaceControl拷贝到outSurfaceControl,返回给app侧
surfaceController.getSurfaceControl(outSurfaceControl);
ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);
} else {
ProtoLog.w(WM_ERROR, "Failed to create surface control for %s", win);
outSurfaceControl.release();
}
return result;
}
1.4.2 WindowStateAnimator.createSurfaceLocked
WindowSurfaceController createSurfaceLocked() {
final WindowState w = mWin;
// 如果创建过则不重复创建
if (mSurfaceController != null) {
return mSurfaceController;
}
// 重置标识位
w.setHasSurface(false);
// 设置DrawState为DRAW_PENDING,因为这里就要创建Surface了,不再是NO_SURFACE状态了
resetDrawState();
mService.makeWindowFreezingScreenIfNeededLocked(w);
int flags = SurfaceControl.HIDDEN;
final WindowManager.LayoutParams attrs = w.mAttrs;
// 根据WindowState里面的属性设置Surface的flag
// Surface是否是Secure(安全layer不能录屏截图)
if (w.isSecureLocked()) {
flags |= SurfaceControl.SECURE;
}
// SKIP_SCREENSHOT在截图和录屏时候不会看到
if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {
flags |= SurfaceControl.SKIP_SCREENSHOT;
}
try {
final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
// 新建WindowSurfaceController,会构造一个SurfaceContorl
// 这个构造函数我们在SurfaceFlinger和端侧Binder框架文章中介绍过了。这里就不细看了。
mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), format,
flags, this, attrs.type);
mSurfaceController.setColorSpaceAgnostic(w.getPendingTransaction(),
(attrs.privateFlags & LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC) != 0);
// 创建完成后设置hasSurface为true
w.setHasSurface(true);
// 处理Input窗口变化
w.mInputWindowHandle.forceChange();
} catch (OutOfResourcesException e) {
Slog.w(TAG, "OutOfResourcesException creating surface");
mService.mRoot.reclaimSomeSurfaceMemory(this, "create", true);
mDrawState = NO_SURFACE;
return null;
} catch (Exception e) {
Slog.e(TAG, "Exception creating surface (parent dead?)", e);
mDrawState = NO_SURFACE;
return null;
}
// ...
}
1.5 WindowSurfacePlacer.performSurfacePlacement
final void performSurfacePlacement(boolean force) {
// 如果还有需要延迟layout还没执行,这里计数一下延迟的请求个数就返回了。(当参数force为true会忽略延迟逻辑)
if (mDeferDepth > 0 && !force) {
mDeferredRequests++;
return;
}
int loopCount = 6;
do {
mTraversalScheduled = false;
// 这里循环调用performSurfacePlacementLoop,详见1.6
// 如果每次循环中发现还需要再次布局,就会设置mTraversalScheduled为true
performSurfacePlacementLoop();
mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
loopCount--;
} while (mTraversalScheduled && loopCount > 0);
mService.mRoot.mWallpaperActionPending = false;
}
1.6 WindowSurfacePlacer.performSurfacePlacementLoop
主要是调用performSurfacePlacement做实际的layout操作,其余的基本都做了注释。
private void performSurfacePlacementLoop() {
// 如果正在Layout,直接return,防止重入
if (mInLayout) {
// ...
return;
}
final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
// 如果配置有变化未更新,先不做layout
if (defaultDisplay.mWaitingForConfig) {
return;
}
if (!mService.mDisplayReady) {
return;
}
mInLayout = true;
// mForceRemoves内存不足时记录要强制删除的窗口
if (!mService.mForceRemoves.isEmpty()) {
// 这里将窗口移除
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 {
// 调用RootWindowContainer.performSurfacePlacement,详见1.7
mService.mRoot.performSurfacePlacement();
mInLayout = false;
// 如果isLayoutNeeded被在上面layout流程中被配置为true,则需要下一次循环继续执行performSurfacePlacementLoop
if (mService.mRoot.isLayoutNeeded()) {
if (++mLayoutRepeatCount < 6) {
// 请求下一次layout,会配置mTraversalScheduled为true。
requestTraversal();
} else {
Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
mLayoutRepeatCount = 0;
}
} else {
mLayoutRepeatCount = 0;
}
if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) {
mService.mH.removeMessages(REPORT_WINDOWS_CHANGE);
mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE);
}
} catch (RuntimeException e) {
mInLayout = false;
Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
}
}
1.7 RootWindowContainer.performSurfacePlacement
调用了performSurfacePlacementNoTrace
void performSurfacePlacement() {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement");
try {
// 详见1.8
performSurfacePlacementNoTrace();
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
1.8 RootWindowContainer.performSurfacePlacementNoTrace
核心的布局逻辑是调用了applySurfaceChangesTransaction,其余有一些壁纸,系统导航键等系统ui,焦点等处理。
void performSurfacePlacementNoTrace() {
int i;
// 如果焦点窗口变化,更新焦点窗口。(关于焦点我们后续在学习Input的时候再研究)
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++;
final DisplayContent defaultDisplay = mWmService.getDefaultDisplayContentLocked();
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
// openTransaction在SurfaceFlinger Transcation章节介绍过。
// 就是配置一个全局的Transcation,后续的窗口变化都会通过这个Transcation传给SurfaceFlinger
mWmService.openSurfaceTransaction();
try {
// 处理窗口布局,详见1.9
applySurfaceChangesTransaction();
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
// 提交Window改变到SurfaceFlinger
mWmService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
// 发送PendingEvent给system_ui
mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
mWmService.mAtmService.mTaskFragmentOrganizerController.dispatchPendingEvents();
mWmService.mSyncEngine.onSurfacePlacement();
mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
// 处理app切换
checkAppTransitionReady(surfacePlacer);
// 如果有需要,处理最近任务的动画(如果壁纸还没有准备好,延迟最近任务动画)
final RecentsAnimationController recentsAnimationController =
mWmService.getRecentsAnimationController();
if (recentsAnimationController != null) {
recentsAnimationController.checkAnimationReady(defaultDisplay.mWallpaperController);
}
// 导航键动画
mWmService.mAtmService.mBackNavigationController
.checkAnimationReady(defaultDisplay.mWallpaperController);
// 壁纸变化标记pendingLayoutChanges
for (int displayNdx = 0; displayNdx < mChildren.size(); ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
if (displayContent.mWallpaperMayChange) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
}
// 再次确认焦点窗口变化
if (mWmService.mFocusMayChange) {
mWmService.mFocusMayChange = false;
mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
false /*updateInputWindows*/);
}
if (isLayoutNeeded()) {
defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
}
// 处理mResizingWindows里面大小变化的窗口。调用WindowState的reportResized,里面会通知client侧。
handleResizingWindows();
// ...
// 横竖屏切换完成,解除冻屏
if (mOrientationChangeComplete) {
if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
mWmService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
mWmService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
}
mWmService.stopFreezingDisplayLocked();
}
// 处理mDestroySurface窗口
i = mWmService.mDestroySurface.size();
if (i > 0) {
do {
i--;
WindowState win = mWmService.mDestroySurface.get(i);
win.mDestroying = false;
final DisplayContent displayContent = win.getDisplayContent();
// 如果当前Input焦点窗口是remove窗口
if (displayContent.mInputMethodWindow == win) {
displayContent.setInputMethodWindowLocked(null);
}
// 如果销毁的窗口是壁纸
if (displayContent.mWallpaperController.isWallpaperTarget(win)) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
// 销毁窗口Surface
win.destroySurfaceUnchecked();
} while (i > 0);
mWmService.mDestroySurface.clear();
}
// 如果之前设置了pendingLayoutChanges,则配置mLayoutNeeded为true
// 设置为true,在接下去的DisplayContent.performLayoutNoTrace才会进行布局计算。
for (int displayNdx = 0; displayNdx < mChildren.size(); ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
if (displayContent.pendingLayoutChanges != 0) {
displayContent.setLayoutNeeded();
}
}
if (!mWmService.mDisplayFrozen) {
final float brightnessOverride = mScreenBrightnessOverride < PowerManager.BRIGHTNESS_MIN
|| mScreenBrightnessOverride > PowerManager.BRIGHTNESS_MAX
? PowerManager.BRIGHTNESS_INVALID_FLOAT : mScreenBrightnessOverride;
int brightnessFloatAsIntBits = Float.floatToIntBits(brightnessOverride);
mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightnessFloatAsIntBits,
0).sendToTarget();
mHandler.obtainMessage(SET_USER_ACTIVITY_TIMEOUT, mUserActivityTimeout).sendToTarget();
}
if (mSustainedPerformanceModeCurrent != mSustainedPerformanceModeEnabled) {
mSustainedPerformanceModeEnabled = mSustainedPerformanceModeCurrent;
mWmService.mPowerManagerInternal.setPowerMode(
Mode.SUSTAINED_PERFORMANCE,
mSustainedPerformanceModeEnabled);
}
// 处理屏幕旋转。
if (mUpdateRotation) {
ProtoLog.d(WM_DEBUG_ORIENTATION, "Performing post-rotate rotation");
mUpdateRotation = updateRotationUnchecked();
}
if (!mWmService.mWaitingForDrawnCallbacks.isEmpty()
|| (mOrientationChangeComplete && !isLayoutNeeded()
&& !mUpdateRotation)) {
mWmService.checkDrawnWindowsLocked();
}
forAllDisplays(dc -> {
// 更新Input目标窗口
dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
dc.updateSystemGestureExclusion();
dc.updateKeepClearAreas();
dc.updateTouchExcludeRegion();
});
mWmService.enableScreenIfNeededLocked();
mWmService.scheduleAnimationLocked();
}
1.9 RootWindowContainer.applySurfaceChangesTransaction
处理放置几个特殊层级。循环遍历每个DisplayContent,调用applySurfaceChangesTransaction进行layout
private void applySurfaceChangesTransaction() {
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();
if (mWmService.mWatermark != null) {
// 水印层
mWmService.mWatermark.positionSurface(defaultDw, defaultDh, t);
}
if (mWmService.mStrictModeFlash != null) {
// 严格模式四周的红框提示层
mWmService.mStrictModeFlash.positionSurface(defaultDw, defaultDh, t);
}
if (mWmService.mEmulatorDisplayOverlay != null) {
// 模拟器显示层(没用过)
mWmService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
defaultDc.getRotation(), t);
}
final int count = mChildren.size();
for (int j = 0; j < count; ++j) {
final DisplayContent dc = mChildren.get(j);
// 循环DisplayContent,调用applySurfaceChangesTransaction,做layout处理,详见1.10
dc.applySurfaceChangesTransaction();
}
// 通知DMS,让它有机会调整旋转等属性。
mWmService.mDisplayManagerInternal.performTraversal(t);
if (t != defaultDc.mSyncTransaction) {
SurfaceControl.mergeToGlobalTransaction(t);
}
}
1.10 DisplayContent.applySurfaceChangesTransaction
处理窗口布局计算。
遍历所有窗口执行performLayout进行窗口大小位置计算。
遍历所有窗口执行mApplySurfaceChangesTransaction,会对窗口的DrawState进行修改,将窗口状态从COMMIT_DRAW_PENDING ->READY_TO_SHOW->HAS_DRAWN,之前提过app侧draw完成会通知WMS将窗口状态改到COMMIT_DRAW_PENDING,而在这里会将窗口改到READY_TO_SHOW/HAS_DRAWN。
递归调用所有窗口的prepareSurfaces,会对所有窗口Surface进行真正的修改,修改通过同一个Transcation传到SurfaceFlinger。
void applySurfaceChangesTransaction() {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
beginHoldScreenUpdate();
mTmpUpdateAllDrawn.clear();
// 处理壁纸窗口
if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
mWallpaperController.adjustWallpaperWindows();
}
if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
// 如果更新了横竖屏
if (updateOrientation()) {
// 设置需要重新布局
setLayoutNeeded();
// 分发Congiguration
sendNewConfiguration();
}
}
if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
setLayoutNeeded();
}
// 执行Layout,详见1.11
performLayout(true /* initial */, false /* updateInputWindows */);
pendingLayoutChanges = 0;
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyPostLayoutPolicy");
try {
mDisplayPolicy.beginPostLayoutPolicyLw();
// 遍历所有窗口,处理system_ui的窗口和它重叠时,根据窗口来决定导航栏,状态栏等的正反色
forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
mDisplayPolicy.finishPostLayoutPolicyLw();
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
// Insets计算,如果Insets改变这里会通知前台窗口等。同时如果Insets有更新是会重新触发布局方法的
// 因为当Insets变化了,窗口大小位置等也可能发生变化,需要重新计算。
mInsetsStateController.onPostLayout();
mTmpApplySurfaceChangesTransactionState.reset();
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applyWindowSurfaceChanges");
try {
// 详见1.12
forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
// 详见1.13
prepareSurfaces();
mInsetsStateController.getImeSourceProvider().checkShowImePostLayout();
mLastHasContent = mTmpApplySurfaceChangesTransactionState.displayHasContent;
if (!inTransition() && !mDisplayRotation.isRotatingSeamlessly()) {
mWmService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
mLastHasContent,
mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredModeId,
mTmpApplySurfaceChangesTransactionState.preferredMinRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferredMaxRefreshRate,
mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
mTmpApplySurfaceChangesTransactionState.disableHdrConversion,
true /* inTraversal, must call performTraversalInTrans... below */);
}
// 通知更新录屏相关
updateRecording();
// 壁纸可见性变化通知
final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
if (wallpaperVisible != mLastWallpaperVisible) {
mLastWallpaperVisible = wallpaperVisible;
mWmService.mWallpaperVisibilityListeners.notifyWallpaperVisibilityChanged(this);
}
while (!mTmpUpdateAllDrawn.isEmpty()) {
final ActivityRecord activity = mTmpUpdateAllDrawn.removeLast();
// updateAllDrawn判断是否所有相关窗口都已经绘制完成,如果还有没有绘制完成的,设置setLayoutNeeded,就会进行下一次绘制。
activity.updateAllDrawn();
}
finishHoldScreenUpdate();
}
1.11 DisplayContent.performLayout
performLayout做了trace,然后调用了performLayoutNoTrace,而performLayoutNoTrace分别调用mPerformLayout和mPerformLayoutAttached对所有未Attach对窗口和已经Attached对窗口进行Layout。
forAllWindows是遍历DisplayContent所有的Window,在WMS中非常常用。
void performLayout(boolean initial, boolean updateInputWindows) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performLayout");
try {
// 执行performLayoutNoTrace
performLayoutNoTrace(initial, updateInputWindows);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
private void performLayoutNoTrace(boolean initial, boolean updateInputWindows) {
// 如果没有配置mLaoutNeeded,直接返回
if (!isLayoutNeeded()) {
return;
}
clearLayoutNeeded();
int seq = mLayoutSeq + 1;
if (seq < 0) seq = 0;
mLayoutSeq = seq;
mTmpInitial = initial;
// 先Layout未attach的WindowState,详见1.11.1
forAllWindows(mPerformLayout, true /* traverseTopToBottom */);
// 再Layout attached的窗口,详见1.11.3
forAllWindows(mPerformLayoutAttached, true /* traverseTopToBottom */);
// 布局计算后,Input焦点窗口可能变化,重新更新一下。
mInputMonitor.setUpdateInputWindowsNeededLw();
if (updateInputWindows) {
mInputMonitor.updateInputWindowsLw(false /*force*/);
}
}
1.11.1 mPerformLayout
对每个未Attach上的窗口调用layoutWindowLw布局,如果该窗口首次布局,记录计算出来的大小到mLastFrame
private final Consumer<WindowState> mPerformLayout = w -> {
if (w.mLayoutAttached) {
return;
}
final boolean gone = w.isGoneForLayout();
// ... log
// 如果窗口已经消失,就不处理了。
if (!gone || !w.mHaveFrame || w.mLayoutNeeded) {
if (mTmpInitial) {
w.resetContentChanged();
}
w.mSurfacePlacementNeeded = true;
w.mLayoutNeeded = false;
final boolean firstLayout = !w.isLaidOut();
// 计算窗口大小位置等,详见1.11.2
getDisplayPolicy().layoutWindowLw(w, null, mDisplayFrames);
w.mLayoutSeq = mLayoutSeq;
if (firstLayout) {
// 将Frame记录作为WindowState等mLastFrame
if (!w.getFrame().isEmpty()) {
w.updateLastFrames();
}
w.onResizeHandled();
}
}
};
1.11.2 DisplayPolicy.layoutWindowLw
调用computeFrames计算窗口大小。
public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
if (win.skipLayout()) {
return;
}
displayFrames = win.getDisplayFrames(displayFrames);
final WindowManager.LayoutParams attrs = win.mAttrs.forRotation(displayFrames.mRotation);
sTmpClientFrames.attachedFrame = attached != null ? attached.getFrame() : null;
// 比较窗口属性rotation,只有rotation相同大小才有效
final boolean trustedSize = attrs == win.mAttrs;
final int requestedWidth = trustedSize ? win.mRequestedWidth : UNSPECIFIED_LENGTH;
final int requestedHeight = trustedSize ? win.mRequestedHeight : UNSPECIFIED_LENGTH;
// 这个方法详见1.3.1,和之前客户端计算大小的逻辑是一样的
mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
win.getRequestedVisibleTypes(), win.mGlobalScale, sTmpClientFrames);
// 将计算好的大小也存在WindowState的frame中。
win.setFrames(sTmpClientFrames, win.mRequestedWidth, win.mRequestedHeight);
}
1.11.3 mPerformLayoutAttached
对每个Attach上的窗口调用layoutWindowLw布局,区别只有判断首次布局里面的逻辑
private final Consumer<WindowState> mPerformLayoutAttached = w -> {
if (!w.mLayoutAttached) {
return;
}
if ((w.mViewVisibility != GONE && w.mRelayoutCalled) || !w.mHaveFrame
|| w.mLayoutNeeded) {
if (mTmpInitial) {
w.resetContentChanged();
}
w.mSurfacePlacementNeeded = true;
w.mLayoutNeeded = false;
getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames);
w.mLayoutSeq = mLayoutSeq;
}
};
1.12 mApplySurfaceChangesTransaction
主要调用commitFinishDrawingLocked进行窗口状态的更新,会将COMMIT_DRAW_PENDING状态改到READY_TO_SHOW,HAS_DRAWN。
private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
// 判断窗口遮蔽状态是否变化
final boolean obscuredChanged = w.mObscured !=
mTmpApplySurfaceChangesTransactionState.obscured;
final RootWindowContainer root = mWmService.mRoot;
w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;
// 如果窗口没有遮蔽
if (!mTmpApplySurfaceChangesTransactionState.obscured) {
final boolean isDisplayed = w.isDisplayed();
if (isDisplayed && w.isObscuringDisplay()) {
// 窗口完全覆盖了后面的窗口
mObscuringWindow = w;
mTmpApplySurfaceChangesTransactionState.obscured = true;
}
// 判断屏幕是否有内容
final boolean displayHasContent = root.handleNotObscuredLocked(w,
mTmpApplySurfaceChangesTransactionState.obscured,
mTmpApplySurfaceChangesTransactionState.syswin);
if (!mTmpApplySurfaceChangesTransactionState.displayHasContent
&& !getDisplayPolicy().isWindowExcludedFromContent(w)) {
mTmpApplySurfaceChangesTransactionState.displayHasContent |= displayHasContent;
}
if (w.mHasSurface && isDisplayed) {
if ((w.mAttrs.flags & FLAG_KEEP_SCREEN_ON) != 0) {
mTmpHoldScreenWindow = w;
} else if (w == mLastWakeLockHoldingWindow) {
// ...
}
final int type = w.mAttrs.type;
if (type == TYPE_SYSTEM_DIALOG
|| type == TYPE_SYSTEM_ERROR
|| (type == TYPE_NOTIFICATION_SHADE
&& mWmService.mPolicy.isKeyguardShowing())) {
mTmpApplySurfaceChangesTransactionState.syswin = true;
}
// ... 刷新率配置等
}
}
// 更新壁纸可见性。
if (obscuredChanged && w.isVisible() && mWallpaperController.isWallpaperTarget(w)) {
mWallpaperController.updateWallpaperVisibility();
}
w.handleWindowMovedIfNeeded();
final WindowStateAnimator winAnimator = w.mWinAnimator;
w.resetContentChanged();
if (w.mHasSurface) {
// 会更新窗口状态,详见1.12.1
final boolean committed = winAnimator.commitFinishDrawingLocked();
if (isDefaultDisplay && committed) {
if (w.hasWallpaper()) {
mWallpaperMayChange = true;
pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
}
}
final ActivityRecord activity = w.mActivityRecord;
if (activity != null && activity.isVisibleRequested()) {
activity.updateLetterboxSurface(w);
// 如果Activity关心的窗口还没有全部绘制完成,加入到mTmpUpdateAllDrawn
// 后续遍历完所有窗口后,再次对mTmpUpdateAllDrawn里的activity检查
final boolean updateAllDrawn = activity.updateDrawnWindowStates(w);
if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(activity)) {
mTmpUpdateAllDrawn.add(activity);
}
}
w.updateResizingWindowIfNeeded();
};
1.12.1 commitFinishDrawingLocked
将窗口状态从COMMIT_DRAW_PENDING ->READY_TO_SHOW->HAS_DRAWN。
boolean commitFinishDrawingLocked() {
if (mDrawState != COMMIT_DRAW_PENDING && mDrawState != READY_TO_SHOW) {
return false;
}
mDrawState = READY_TO_SHOW;
boolean result = false;
final ActivityRecord activity = mWin.mActivityRecord;
if (activity == null || activity.canShowWindows()
|| mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
// 会将窗口状态改成HAS_DRAWN。
result = mWin.performShowLocked();
}
return result;
}
1.13 DisplayContent.prepareSurfaces
super.prepareSurfaces是WindowContainer.prepareSurfaces,会遍历所有子节点的prepareSurfaces,这里会操作窗口的Surface大小位置,存储在公用的Transcation后续会传给SurfaceFlinger。
我们主要看一下WindowState.prepareSurfaces,详见1.13.1
void prepareSurfaces() {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareSurfaces");
try {
// DisplayContent共用Transcation
final Transaction transaction = getPendingTransaction();
// WindowContainer.prepareSurfaces,调用了每个子节点的prepareSurfaces
// 里面有窗口实际的大小位置操作,存储到Transcation后续通知SurfaceFlinger
super.prepareSurfaces();
SurfaceControl.mergeToGlobalTransaction(transaction);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
1.13.1 WindowState.prepareSurfaces
void prepareSurfaces() {
mIsDimming = false;
// 有Surface
if (mHasSurface) {
applyDims();
// 更新Surface位置信息
updateSurfacePositionNonOrganized();
updateFrameRateSelectionPriorityIfNeeded();
// 更新Surface缩放大小
updateScaleIfNeeded();
mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
}
super.prepareSurfaces();
}
小结
本节介绍了窗口布局过程,这个流程细节很多,我们省略了很多细节,关注主要流程。
首先介绍了窗口在WMS的几种状态。
其次app performTraversals中主要做的事是Measure,Layout,Draw。Draw完成后会通知WMS将窗口状态更新至COMMIT_DRAW_PENDING。还有最关键调用relayoutWindow。
WMS relayout会布局以及计算所有窗口大小位置,没有Surface的窗口可能会创建Surface,在计算完成后还会通知SurfaceFlinger更新Surface