常見的WindowManager問題分析

1.UI hang and adb is still alive when running LGE compliant monkey test with DUT for 771 Minutes
WindowManagerService主要修改點是在performLayoutAndPlacesurfaceLockedInner(主要用於系統UI刷新)這個方法
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ec566bc..0cc29f6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -10195,7 +10195,12 @@
                 // Don't remove this window until rotation has completed.
                 continue;
             }
-            win.reportResized();
+            if (!win.reportResized()) {
+                mInnerFields.mOrientationChangeComplete = true;
+                if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
+                    "win: " + win + " Resize have exception, set orientationChangeComplete to "
+                    + mInnerFields.mOrientationChangeComplete);
+            }
             mResizingWindows.remove(i);
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c2548de..5dd05c5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1484,7 +1484,7 @@
         }
     }
 
-    void reportResized() {
+    boolean reportResized() {
         try {
             if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
                     + ": " + mCompatFrame);
@@ -1540,8 +1540,21 @@
             mStableInsetsChanged = false;
             mOutsetsChanged = false;
             mWinAnimator.mSurfaceResized = false;
+            return true;
         } catch (RemoteException e) {
             mOrientationChanging = false;
+            if (DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) {
+                Slog.i(TAG, "Fail to resize window " + this + ": " + e);
+            }
+            mOverscanInsetsChanged = false;
+            mContentInsetsChanged = false;
+            mVisibleInsetsChanged = false;
+            mStableInsetsChanged = false;
+            mWinAnimator.mSurfaceResized = false;
+            mLastOverscanInsets.set(mOverscanInsets);
+            mLastContentInsets.set(mContentInsets);
+            mLastVisibleInsets.set(mVisibleInsets);
+            mLastStableInsets.set(mStableInsets);
             mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
                     - mService.mDisplayFreezeTime);
             // We are assuming the hosting process is dead or in a zombie state.
@@ -1549,6 +1562,7 @@
                     + ", removing this window.");
             mService.mPendingRemove.add(this);
             mService.requestTraversalLocked();
+            return false;
         }
     }

死循環在哪裏?

1、Window退出調用WindowManagerServiceremoveWindowLocked

2、removeWindowLocked會執行退場動畫,並調用performLayoutAndPlaceSurfacesLocked進行一次計算和狀態處理並將動畫進行調度處理,放入下一個VSYNC的處理列表中因爲動畫還沒有被執行處理所以mInnerFields.mOrientationChangeComplete爲true,因此mWindowsFreezingScreen也不會被置爲false,屏幕和輸入不會被解凍和恢復。

3、ActivityManagerService接收到app died的通知之後resume下一個app,下一個app與當前結束的這個app的orientation不一樣,觸發凍結屏幕和輸入

4、VSYNC到來,執行動畫的相關操作,因爲屏幕已經被凍結,所以正在退出Window不能執行動畫操作直接返回,導致finishExit不能被執行,最終Window不會正常刪除。執行copyAnimToLayoutParamsLockedmInnerFields.mOrientationChangeComplete置爲true然後調用requestTraversalLocked發送執行下一次performLayoutAndPlaceSurfacesLocked消息到消息隊列中

5、performLayoutAndPlaceSurfacesLocked執行調用updateResizingWindows因爲退出Window沒有被finishExit,並且執行reportResized更新窗口大小和內容狀態的過程中由於Window已經退出所以調用mClient.resized執行IPC(跨進程調用)發生RemoteException,導致關鍵狀態值沒有被置位清空,所以執行updateResizingWindows過程中會因爲Window的狀態一直滿足條件而調用makeWindowFreezingScreenIfNeededLocked,因爲此時窗口已經被凍結,所以將mInnerFields.mOrientationChangeComplete一直置爲false,因此不會mWindowsFreezingScreen置爲false和調用stopFreezingDisplayLocked解凍屏幕和恢復輸入。接着調用scheduleAnimationLocked下一次動畫調度VSYNC的列表中

6、下一次VSYNC到來重複第四步和第五步構成不能解凍屏幕和恢復輸入的死循環


2.Update window surface while live wallpaper is changed.

Other than surface resized or surface moved, setSurfaceBoundariesLocked inWindowStateAnimator.java may encounter another scenario that the live wallpaperis changed. In all of scenarios, updateSurfaceWindowCrop(...) should be calledseparately to avoid float window flickering when it's dragged off screen.

  void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
  ...
      if ((w.mAttrs.flags & LayoutParams.FLAG_FULLSCREEN) != 0
  +              || w.mAttrs.type == LayoutParams.TYPE_WALLPAPER) {
            updateSurfaceWindowCrop(recoveringMemory);
        }
    }


問題:窗口邊緣切換的時候出現閃爍
思路:
When the window move to the edge of screen, first call setWindowCrop,
 if the position of window is changed, second call setPosition. setWindowCrop will let surfaceflinger dispaly the window,
 but the lefttop position is the last postion, this will lead the rightbottom position reduced,
 and the reduced rect is dispaly the second layer's window,
 so the window flicking. setPosition let surfaceflinger dispaly the window second, and this time is right rect.
路徑:
        services/core/java/com/android/server/wm/WindowStateAnimator.java
        
     

   void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
        final WindowState w = mWin;

        int width;
        int height;
        if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
            // for a scaled surface, we always want the requested
            // size.
            width  = w.mRequestedWidth;
            height = w.mRequestedHeight;
        } else {
            width = w.mCompatFrame.width();
            height = w.mCompatFrame.height();
        }

        // Something is wrong and SurfaceFlinger will not like this,
        // try to revert to sane values
        if (width < 1) {
            width = 1;
        }
        if (height < 1) {
            height = 1;
        }

        float left = w.mShownFrame.left;
        float top = w.mShownFrame.top;

        // Adjust for surface insets.
        final LayoutParams attrs = w.getAttrs();
        width += attrs.surfaceInsets.left + attrs.surfaceInsets.right;
        height += attrs.surfaceInsets.top + attrs.surfaceInsets.bottom;
        left -= attrs.surfaceInsets.left;
        top -= attrs.surfaceInsets.top;

        final boolean surfaceMoved = mSurfaceX != left || mSurfaceY != top;
        if (surfaceMoved) {
            mSurfaceX = left;
            mSurfaceY = top;

            try {
                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
                        "POS " + left + ", " + top, null);
                mSurfaceControl.setPosition(left, top);
          +      updateSurfaceWindowCrop(recoveringMemory);
            } catch (RuntimeException e) {
                Slog.w(TAG, "Error positioning surface of " + w
                        + " pos=(" + left + "," + top + ")", e);
                if (!recoveringMemory) {
                    mService.reclaimSomeSurfaceMemoryLocked(this, "position", true);
                }
            }
        }

        final boolean surfaceResized = mSurfaceW != width || mSurfaceH != height;
        if (surfaceResized) {
            mSurfaceW = width;
            mSurfaceH = height;
            mSurfaceResized = true;

            try {
                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
                        "SIZE " + width + "x" + height, null);
                mSurfaceControl.setSize(width, height);
            +    updateSurfaceWindowCrop(recoveringMemory);
                mAnimator.setPendingLayoutChanges(w.getDisplayId(),
                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {
                    final TaskStack stack = w.getStack();
                    if (stack != null) {
                        stack.startDimmingIfNeeded(this);
                    }
                }
            } catch (RuntimeException e) {
                // If something goes wrong with the surface (such
                // as running out of memory), don't take down the
                // entire system.
                Slog.e(TAG, "Error resizing surface of " + w
                        + " size=(" + width + "x" + height + ")", e);
                if (!recoveringMemory) {
                    mService.reclaimSomeSurfaceMemoryLocked(this, "size", true);
                }
            }
        }
       -         updateSurfaceWindowCrop(recoveringMemory);
    }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章