问题处理:横竖屏切换时页面显示异常

it2024-08-20  45

横竖屏切换时页面显示异常

问题现象分析发现问题解决问题

问题现象

版本:android P + Docker现象:运行王者荣耀游戏,在付款页面返回游戏页面时,发生竖屏到横屏的切换,游戏页面显示不正常,仅显示半个页面,右半面显示黑色。

分析

首先是横竖屏切换的代码,主要是在windowsmanagerservice里面处理的。 参考了: Android 7.1 屏幕旋转流程分析 Android 7.1 WindowManagerService 屏幕旋转流程分析 (二) Android 7.1 WindowManagerService 屏幕旋转流程分析 (三) Android 7.1 ActivityManagerService 屏幕旋转流程分析 (四) WindowManagerService 大致完成三件事,首先更新屏幕方向,然后具体实施屏幕旋转,最后通知AMS configuration变更。 framework/base/services/core/java/com/android/server/wm/WindowManagerService.java 3858: private void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) { 这个函数即首先调用displayContent.updateRotationUnchecked();更新rotation,然后调用performSurfacePlacement()做屏幕的绘制,最后调用sendNewConfiguration()发送Configuration变更事件。

发现问题

通过dumpsys SurfaceFlinger 看layer,发现有问题的layer显示区域不对,应该显示横屏的仍然以竖屏方式显示由于这个问题是偶现的问题,开始以为是performance的问题,在显示绘制前加了100ms的延迟,问题可以解决,但切换时卡顿严重: frameworks/base/services/core/java/com/android/server/wm/WindowSurfacePlacer.java 148: final void performSurfacePlacement(boolean force) { … int loopCount = 6;

/* try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } */ do { mTraversalScheduled = false;

因为最终是在SurfaceFlinger里面进行合成显示,需要在java和native间调用切换,通过增加log,最终发现是请求切换的高宽没有送到native层 正确log: 10-16 10:31:23.744 141 141 E Layer : doTransaction geometry (layer=0x714a93067000 ‘com.tencent.tmgp.sgame/com.tencent.midas.proxyactivity.APMidasPayProxyActivity#1’), req(1280, 672) >cur (720, 1232), sizeChanged: 1 错误log: 10-16 10:31:23.744 141 141 E Layer : doTransaction geometry (layer=0x714a93067000 ‘com.tencent.tmgp.sgame/com.tencent.midas.proxyactivity.APMidasPayProxyActivity#1’), req(720, 1280) >cur (720, 1232), sizeChanged: 1

向上跟踪, 发现是setSize没有执行: framework/nativelibs/gui/SurfaceComposerClient.cpp

SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize( const sp& sc, uint32_t w, uint32_t h) {

这个是native的api, base里面调过来的,在setSurfaceBoundariesLocked里面有个开关mInRelayout, 发生错误的时候这个值是false。 services/core/java/com/android/server/wm/WindowStateAnimator.java void setSurfaceBoundariesLocked(final boolean recoveringMemory) {

final boolean relayout = !w.mRelayoutCalled || w.mInRelayout; if (relayout) { mSurfaceResized = mSurfaceController.setSizeInTransaction( mTmpSize.width(), mTmpSize.height(), recoveringMemory); } else {

解决问题

增加一个tag,判断其页面高宽发生变化后更新size。patch:在这里插入代码片…/java/com/android/server/wm/WindowManagerService.java | 3 +++ …/core/java/com/android/server/wm/WindowState.java | 9 +++++++++ …/java/com/android/server/wm/WindowStateAnimator.java | 2 ± 3 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 7a2c28bd5c8…730afb59227 100644 — a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1975,6 +1975,9 @@ public class WindowManagerService extends IWindowManager.Stub

win.mRelayoutCalled = true; win.mInRelayout = true; if (requestedWidth != win.mFrame.width() || requestedWidth != win.mRequestedWidth ||win.isNeedReLayout()) { win.mNeedRelayout = true; } win.mViewVisibility = viewVisibility; if (DEBUG_SCREEN_ON) {

diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index bee70a01194…d2d7984529e 100644 — a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -475,6 +475,8 @@ class WindowState extends WindowContainer implements WindowManagerP

boolean mInRelayout;

boolean mNeedRelayout;

/** * If the application has called relayout() with changes that can * impact its window’s size, we need to perform a layout pass on it @@ -1550,6 +1552,13 @@ class WindowState extends WindowContainer implements WindowManagerP && !mAnimatingExit && !mDestroying; }

boolean isNeedReLayout() {

if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) { return true; } return false;

}

/** * Is this window currently on-screen? It is on-screen either if it * is visible or it is currently running an animation before no longer diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 410e1587924…beb8479d5bf 100644 — a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -888,7 +888,7 @@ class WindowStateAnimator { // However, this would be unsafe, as the client may be in the middle // of producing a frame at the old size, having just completed layout // to find the surface size changed underneath it.

final boolean relayout = !w.mRelayoutCalled || w.mInRelayout; final boolean relayout = !w.mRelayoutCalled || w.mInRelayout || w.mNeedRelayout; if (relayout) { mSurfaceResized = mSurfaceController.setSizeInTransaction( mTmpSize.width(), mTmpSize.height(), recoveringMemory);

– 2.17.1

最新回复(0)