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

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

问题现象

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

分析

首先是横竖屏切换的代码,主要是在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变更事件。

发现问题

  1. 通过dumpsys SurfaceFlinger 看layer,发现有问题的layer显示区域不对,应该显示横屏的仍然以竖屏方式显示
  2. 由于这个问题是偶现的问题,开始以为是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;

  1. 因为最终是在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

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

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

  1. 这个是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 {

解决问题

  1. 增加一个tag,判断其页面高宽发生变化后更新size。
  2. patch:
  3. 在这里插入代码片
  4. …/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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值