常见的WindowManager问题分析

原创 2016年06月01日 15:47:59
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);
    }


版权声明:本文为博主原创文章,未经博主允许不得转载。

《深入理解Android 卷III》第四章 深入理解WindowManagerService

《深入理解Android 卷III》即将发布,作者是张大伟。此书填补了深入理解Android Framework卷中的一个主要空白,即Android Framework中和UI相关的部分。在一个特别讲...
  • Innost
  • Innost
  • 2015年08月14日 13:18
  • 27644

GUI显示系统之SurfaceFlinger

转载自http://blog.csdn.net/uiop78uiop78/article/details/8954508 介绍了Surface, SurfaceTexture, BufferQueu...

Android WindowManager及其动画问题

lp.windowAnimations = R.style.anim_view;//动画 设置系统动画可能还有效果,设置自己的动画似乎没有什么效果,底部别人提供了自定义的动画,是OK的 转载地址是 ...

surfaceDestroyed什么时候被调用

今天看别人的代码,突然有个疑问,surfaceDestroyed这个函数什么时候被调用呢?     上网搜了一番,基本都说是surface被销毁的时候,才会调用surfaceDestroye...
  • qiuchenl
  • qiuchenl
  • 2011年11月14日 18:30
  • 16837

Android图形系统之Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的联系

/********************************************************************************************  * aut...
  • conowen
  • conowen
  • 2012年08月03日 17:29
  • 51017

RecentsActivity的启动分析一

RecentsActivity是SystemUI用于显示最近使用的应用列表,当用户点击Switch按键时会启动RecentsActivity。先分析启动的过程。首先是用户点击SWITCH按键,Phon...

SetupWizard调试技巧

MSetupWizard源码路径device/厂商/common/apps/MSetupWizard MSetupWizard安装完android系统后第一次启东时出现的让用户选择系统语言等信息的一个...

Android中常见android.view.WindowManager$BadTokenException错误

项目中有时会出现如下的问题: new AlertDialog.Builder(activity).setTitle(getResources().getString(R.string.testspe...

WindowManager添加的Floating窗口对startActivity的影响问题解决(Android)

Activity中设置 android:theme="@android:style/Theme.Dialog" 后,在悬浮按钮中点击无法启动该Activity的问题解决办法。...

WindowManager当前焦点窗口管理,及多用户下当前焦点window错乱问题

android中窗口是由WindowManagerService管理的,其中有一个成员变量mCurrentFocus,记录的是当前的焦点窗口,用于将实时input event传递给这个window处理...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:常见的WindowManager问题分析
举报原因:
原因补充:

(最多只允许输入30个字)