Waiting for drawn Window耗时过长流程梳理

本文深入探讨了负载指纹响应时间过长的问题,特别是在从DRAW_PENDING到HAS_DRAWN状态转换过程中出现的延迟。通过详细的log分析,揭示了Launcher和StatusBar在绘制过程中的耗时情况,并跟踪了DRAW_PENDING和HAS_DRAWN状态的赋值路径,为解决响应时间衰退提供了关键线索。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 存在一个问题:负载指纹响应时间衰退达到1秒多,从log中看Waiting for drawn Window 耗时太长

Line 3204: 08-14 14:44:45.929433  1100  5600 I PowerManagerService: Waking up from sleep (uid=10028 reason=android.policy:FINGERPRINT)...
Line 3211: 08-14 14:44:45.939175  1100  1135 I DisplayPowerController: Blocking screen on until initial contents have been drawn.
///Launcher 处于DRAW_PENDING 状态,这是一个surface已经创建但是Window还没draw的状态
Line 3250: 08-14 14:44:46.462380  1100  1121 I WindowManager: Waiting for drawn Window{f9de4b3 u0  com.android.launcher3/com.android.launcher3.Launcher}: removed=false visible=true mHasSurface=true drawState=1
Line 3251: 08-14 14:44:46.462434  1100  1121 I WindowManager: Waiting for drawn Window{18b56d9 u0 StatusBar}: removed=false visible=true mHasSurface=true drawState=1
///StatusBar HAS_DRAWN 完成绘制
Line 3276: 08-14 14:44:46.757318  1100  1176 I WindowManager: Waiting for drawn Window{18b56d9 u0 StatusBar}: removed=false visible=true mHasSurface=true drawState=4
    ....   
///Launcher 绘制完成持续时间比较久,从14:44:46.462380持续到14:44:47.221558,耗时接近800毫秒
Line 3298: 08-14 14:44:47.221558  1100  1176 I WindowManager: Waiting for drawn Window{f9de4b3 u0  com.android.launcher3/com.android.launcher3.Launcher}: removed=false visible=true mHasSurface=true drawState=4
     08-14 14:44:47.221628  1100  1176 D WindowManager: Window drawn win=Window{f9de4b3 u0 com.android.launcher3/com.android.launcher3.Launcher}
     08-14 14:44:47.221644  1100  1176 D WindowManager: All windows drawn!
     08-14 14:44:47.252180  1100  1135 I DisplayPowerController: Unblocked screen on after 1313 ms
     ///这一次power screen on 耗时1.33S
     08-14 14:44:47.257309  1100  1135 W PowerManagerService: Screen on took 1330 ms

 如上log中drawstate有五个状态,一般是从DRAW_PENDING 开始等待到HAS_DRAWN这一段耗时太长。

/frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
    /** This is set when there is no Surface */
    static final int NO_SURFACE = 0;
    /** This is set after the Surface has been created but before the window has been drawn. During
     * this time the surface is hidden. */
    static final int DRAW_PENDING = 1;
    /** This is set after the window has finished drawing for the first time but before its surface
     * is shown.  The surface will be displayed when the next layout is run. */
    static final int COMMIT_DRAW_PENDING = 2;
    /** This is set during the time after the window's drawing has been committed, and before its
     * surface is actually shown.  It is used to delay showing the surface until all windows in a
     * token are ready to be shown. */
    static final int READY_TO_SHOW = 3;
    /** Set when the window has been shown in the screen the first time. */
    static final int HAS_DRAWN = 4;

往下再看一下DRAW_PENDING和HAS_DRAWN分别是在哪边赋值的。

/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

    void waitForAllWindowsDrawn() {
        final WindowManagerPolicy policy = mService.mPolicy;
        forAllWindows(w -> {
            final boolean keyguard = policy.isKeyguardHostWindow(w.mAttrs);
            if (w.isVisibleLw() && (w.mAppToken != null || keyguard)) {
                w.mWinAnimator.mDrawState = DRAW_PENDING;
                // Force add to mResizingWindows.
                w.mLastContentInsets.set(-1, -1, -1, -1);
                mService.mWaitingForDrawn.add(w);
            }
        }, true /* traverseTopToBottom */);
    }

三个调用的点

1.MSG_KEYGUARD_DRAWN_COMPLETE,

2.MSG_KEYGUARD_DRAWN_TIMEOUT,

3.screenTurningOn

----->PhoneWindowManger.finishKeyguardDrawn----->WindowManagerService.waitForAllWindowsDrawn---->DisplayContent.waitForAllWindowsDrawn

在WindowManagerService的waitForAllWindowsDrawn中

        @Override
        public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
            boolean allWindowsDrawn = false;
            synchronized (mWindowMap) {
                mWaitingForDrawnCallback = callback;
                 //即对应的DisplayContent的waitForAllWindowsDrawn
                getDefaultDisplayContentLocked().waitForAllWindowsDrawn();
//AnimationThread 线程post了一个mPerformSurfacePlacement Runnable,
//mAnimationHandler收到这个消息后,performSurfacePlacement()方法就会 
//执行,接着调用 performSurfacePlacementLoop->RootWindowContainer.performSurfacePlacement,
//AnimationThread 继承 HandlerThread 一个带Looper 的Thread
                mWindowPlacerLocked.requestTraversal();
                mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
                if (mWaitingForDrawn.isEmpty()) {
                    allWindowsDrawn = true;
                } else {
                    mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
                    checkDrawnWindowsLocked();
                }
            }
            if (allWindowsDrawn) {
                callback.run();
            }
        }
//WindowSurfacePlacer.java

    void requestTraversal() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mService.mAnimationHandler.post(mPerformSurfacePlacement);
        }
    }

其中等待绘制的界面不为空走checkDrawnWindowsLocked

    void checkDrawnWindowsLocked() {
        if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
            return;
        }
        for (int j = mWaitingForDrawn.size() - 1; j >= 0; j--) {
            WindowState win = mWaitingForDrawn.get(j);
            if (DEBUG_SCREEN_ON) Slog.i(TAG_WM, "Waiting for drawn " + win +
                    ": removed=" + win.mRemoved + " visible=" + win.isVisibleLw() +
                    " mHasSurface=" + win.mHasSurface +
                    " drawState=" + win.mWinAnimator.mDrawState);
            if (win.mRemoved || !win.mHasSurface || !win.mPolicyVisibility) {
                // Window has been removed or hidden; no draw will now happen, so stop waiting.
                if (DEBUG_SCREEN_ON) Slog.w(TAG_WM, "Aborted waiting for drawn: " + win);
                mWaitingForDrawn.remove(win);
            } else if (win.hasDrawnLw()) {//即等于HAS_DRAWN状态会将win删除
                // Window is now drawn (and shown).
                if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "Window drawn win=" + win);
                mWaitingForDrawn.remove(win);
            }
        }
        if (mWaitingForDrawn.isEmpty()) {
            if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "All windows drawn!");
            mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
            mH.sendEmptyMessage(H.ALL_WINDOWS_DRAWN);
        }
    }

而HAS_DRAWN在frameworks/base/services/core/java/com/android/server/wm/WindowState.java

    // This must be called while inside a transaction.
    boolean performShowLocked() {
        if (isHiddenFromUserLocked()) {
            if (DEBUG_VISIBILITY) Slog.w(TAG, "hiding " + this + ", belonging to " + mOwnerUid);
            hideLw(false);
            return false;
        }

        logPerformShow("performShow on ");

        final int drawState = mWinAnimator.mDrawState;
        if ((drawState == HAS_DRAWN || drawState == READY_TO_SHOW)
                && mAttrs.type != TYPE_APPLICATION_STARTING && mAppToken != null) {
            mAppToken.onFirstWindowDrawn(this, mWinAnimator);
        }

        if (mWinAnimator.mDrawState != READY_TO_SHOW || !isReadyForDisplay()) {
            return false;
        }

        logPerformShow("Showing ");

        mService.enableScreenIfNeededLocked();
        mWinAnimator.applyEnterAnimationLocked();

        // Force the show in the next prepareSurfaceLocked() call.
        mWinAnimator.mLastAlpha = -1;
        if (DEBUG_ANIM) Slog.v(TAG,
                "performShowLocked: mDrawState=HAS_DRAWN in " + this);
        mWinAnimator.mDrawState = HAS_DRAWN;
        mService.scheduleAnimationLocked();

        if (mHidden) {
            mHidden = false;
            final DisplayContent displayContent = getDisplayContent();

            for (int i = mChildren.size() - 1; i >= 0; --i) {
                final WindowState c = mChildren.get(i);
                if (c.mWinAnimator.mSurfaceController != null) {
                    c.performShowLocked();
                    // It hadn't been shown, which means layout not performed on it, so now we
                    // want to make sure to do a layout.  If called from within the transaction
                    // loop, this will cause it to restart with a new layout.
                    if (displayContent != null) {
                        displayContent.setLayoutNeeded();
                    }
                }
            }
        }

        if (mAttrs.type == TYPE_INPUT_METHOD) {
            getDisplayContent().mDividerControllerLocked.resetImeHideRequested();
        }

        return true;
    }

HAS_DRAWN打印的堆栈 

11-07 07:34:46.279 V/WindowManager( 1039): performShowLocked: mDrawState=HAS_DRAWN in Window{b848e17 u0 StatusBar}
11-07 07:34:46.279 V/WindowManager( 1039): java.lang.Throwable
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowState.performShowLocked(WindowState.java:3995)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked(WindowStateAnimator.java:357)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.DisplayContent.lambda$new$8$DisplayContent(DisplayContent.java:843)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.-$$Lambda$DisplayContent$qxt4izS31fb0LF2uo_OF9DMa7gc.accept(Unknown Source:4)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:1184)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:1174)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4194)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowState.forAllWindows(WindowState.java:4093)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:883)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:883)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.DisplayContent.forAllWindows(DisplayContent.java:2149)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:900)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:3778)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:834)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:611)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:568)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:159)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:105)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:95)
11-07 07:34:46.279 V/WindowManager( 1039): 	at com.android.server.wm.WindowSurfacePlacer.lambda$new$0$WindowSurfacePlacer(WindowSurfacePlacer.java:62)

WindowAnimator.animate----->WindowContainer.checkAppWindowsReadyToShow--->AppWindowToken.checkAppWindowsReadyToShow--->AppWindowToken.showAllWindowsLocked---->WindowState.performShowLocked

    /** Checks if all windows in an app are all drawn and shows them if needed. */
    void checkAppWindowsReadyToShow() {
        for (int i = mChildren.size() - 1; i >= 0; --i) {
            final WindowContainer wc = mChildren.get(i);
            wc.checkAppWindowsReadyToShow();
        }
    }
    /**
     * DO NOT HOLD THE WINDOW MANAGER LOCK WHILE CALLING THIS METHOD. Reason: the method closes
     * an animation transaction, that might be blocking until the next sf-vsync, so we want to make
     * sure other threads can make progress if this happens.
     */
    private void animate(long frameTimeNs) {
....
        synchronized (mService.mWindowMap) {
             if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate");
             mService.openSurfaceTransaction();
.....
                final int numDisplays = mDisplayContentsAnimators.size();
                for (int i = 0; i < numDisplays; i++) {
                    final int displayId = mDisplayContentsAnimators.keyAt(i);
                    final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
                    DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);

                    final ScreenRotationAnimation screenRotationAnimation =
                            displayAnimator.mScreenRotationAnimation;
                    if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
                        if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
                            setAnimating(true);
                        } else {
                            mBulkUpdateParams |= SET_UPDATE_ROTATION;
                            screenRotationAnimation.kill();
                            displayAnimator.mScreenRotationAnimation = null;

                            //TODO (multidisplay): Accessibility supported only for the default
                            // display.
                            if (accessibilityController != null && dc.isDefaultDisplay) {
                                // We just finished rotation animation which means we did not
                                // announce the rotation and waited for it to end, announce now.
                                accessibilityController.onRotationChangedLocked(
                                        mService.getDefaultDisplayContentLocked());
                            }
                        }
                    }
                    // Update animations of all applications, including those
                    // associated with exiting/removed apps
                    ++mAnimTransactionSequence;
                    dc.updateWindowsForAnimator(this);
                    dc.updateWallpaperForAnimator(this);
                    dc.prepareSurfaces();
                }
....
                for (int i = 0; i < numDisplays; i++) {
                    final int displayId = mDisplayContentsAnimators.keyAt(i);
                    final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);

                    dc.checkAppWindowsReadyToShow();

                    final ScreenRotationAnimation screenRotationAnimation =
                            mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
                    if (screenRotationAnimation != null) {
                        screenRotationAnimation.updateSurfaces(mTransaction);
                    }
                    orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
                    //TODO (multidisplay): Magnification is supported only for the default display.
                    if (accessibilityController != null && dc.isDefaultDisplay) {
                        accessibilityController.drawMagnifiedRegionBorderIfNeededLocked();
                    }
                }
                if (!mAnimating) {
                    cancelAnimation();
                }

                if (mService.mWatermark != null) {
                    mService.mWatermark.drawIfNeeded();
                }

                SurfaceControl.mergeToGlobalTransaction(mTransaction);
           }finally {
                  mService.closeSurfaceTransaction("WindowAnimator");
                  if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
              }
....
}
....

   }

READY_TO_SHOW的赋值点

1.WindowSurfacePlacer.performSurfacePlacementLoop(){ 
  mService.mRoot.performSurfacePlacement(recoveringMemory);
} 
2.DisplayContent.updateFocusedWindowLocked(){
   mWmService.mRoot.performSurfacePlacement(false);
}
///
RootWindowContainer.performSurfacePlacement(boolean recoveringMemory)-->
RootWindowContainer.performSurfacePlacementNoTrace{ applySurfaceChangesTransaction(recoveringMemory);}
-->
RootWindowContainer.applySurfaceChangesTransaction{
830          final int count = mChildren.size();
831          for (int j = 0; j < count; ++j) {
832              final DisplayContent dc = mChildren.get(j);
833              dc.applySurfaceChangesTransaction(recoveringMemory);
834          }
}
-->
DisplayContent.applySurfaceChangesTransaction{forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);}
-->
DisplayContent.mApplySurfaceChangesTransaction = w -> 
-->
WindowStateAnimator.commitFinishDrawingLocked{ mDrawState = READY_TO_SHOW;}
--->
WindowState.performShowLocked { mDrawState=HAS_DRAWN }--->

 READY_TO_SHOW打印的堆栈

11-07 07:34:46.274 I/WindowManager( 1039): commitFinishDrawingLocked: mDrawState=READY_TO_SHOW Surface(name=StatusBar)/@0x1e834ef
11-07 07:34:46.274 I/WindowManager( 1039): java.lang.Throwable
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowStateAnimator.commitFinishDrawingLocked(WindowStateAnimator.java:350)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.DisplayContent.lambda$new$8$DisplayContent(DisplayContent.java:843)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.-$$Lambda$DisplayContent$qxt4izS31fb0LF2uo_OF9DMa7gc.accept(Unknown Source:4)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:1184)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:1174)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4194)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowState.forAllWindows(WindowState.java:4093)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:883)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:883)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.DisplayContent.forAllWindows(DisplayContent.java:2149)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:900)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:3778)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:834)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace(RootWindowContainer.java:611)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:568)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:159)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:105)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:95)
11-07 07:34:46.274 I/WindowManager( 1039): 	at com.android.server.wm.WindowSurfacePlacer.lambda$new$0$WindowSurfacePlacer(WindowSurfacePlacer.java:62)

一个有锁屏界面按Power键亮屏的界面绘制流程log 

08-21 03:04:57.616 I/PowerManagerService( 1025): Waking up from sleep (uid=1000 reason=android.policy:POWER)...
08-21 03:04:57.619 I/DisplayPowerController( 1025): Blocking screen on until initial contents have been drawn.
08-21 03:04:57.703 I/WindowManager( 1025): Waiting for drawn Window{94a4fbd u0 StatusBar}: removed=false visible=true mHasSurface=true drawState=1
....
08-21 03:04:57.736 I/WindowManager( 1025): Waiting for drawn Window{94a4fbd u0 StatusBar}: removed=false visible=true mHasSurface=true drawState=1
08-21 03:04:57.746 D/WindowManager( 1025): finishDrawingWindow: Window{c72bd2b u0 SmartPanel_SliderView} mDrawState=HAS_DRAWN
08-21 03:04:57.765 D/WindowManager( 1025): finishDrawingWindow: Window{94a4fbd u0 StatusBar} mDrawState=DRAW_PENDING
08-21 03:04:57.766 W/WindowManager( 1025): setLayoutNeeded: callers=com.android.server.wm.WindowState.setDisplayLayoutNeeded:2312 com.android.server.wm.WindowManagerService.finishDrawingWindow:2441 com.android.server.wm.Session.finishDrawing:282 
08-21 03:04:57.766 V/WindowManager( 1025): performSurfacePlacementInner: entry. Called by com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop:208 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement:156 com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement:146 
08-21 03:04:57.766 I/WindowManager( 1025): >>> OPEN TRANSACTION performLayoutAndPlaceSurfaces
....
08-21 03:04:57.772 I/WindowManager( 1025): commitFinishDrawingLocked: mDrawState=READY_TO_SHOW Surface(name=StatusBar)/@0x6490d9c
08-21 03:04:57.772 V/WindowManager( 1025): performShow on Window{94a4fbd u0 StatusBar}: mDrawState=READY_TO_SHOW readyForDisplay=true starting=false during animation: policyVis=true parentHidden=false tok.hiddenRequested=false tok.hidden=false animationSet=false tok animating=false Callers=com.android.server.wm.WindowState.performShowLocked:3891
....
08-21 03:04:57.773 V/WindowManager( 1025): applyAnimation: win=WindowStateAnimator{f7df172 StatusBar} anim=-1 attr=0xffffffff a=null transit=3 isEntrance=true Callers 
08-21 03:04:57.773 V/WindowManager( 1025): performShowLocked: mDrawState=HAS_DRAWN in Window{94a4fbd u0 StatusBar}
...
08-21 03:04:57.776 I/WindowManager( 1025): <<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces
...
08-21 03:04:57.777 I/WindowManager( 1025): Waiting for drawn Window{94a4fbd u0 StatusBar}: removed=false visible=true mHasSurface=true drawState=4
08-21 03:04:57.885 W/PowerManagerService( 1025): Screen on took 278 ms

 log中>>> OPEN TRANSACTION performLayoutAndPlaceSurfaces和<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces对应的是

/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
  void performSurfacePlacement(boolean recoveringMemory) {
.....

        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
        mService.openSurfaceTransaction();
        try {
            applySurfaceChangesTransaction(recoveringMemory, defaultDw, defaultDh);
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
        } finally {
            mService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
        }
....
        mService.mAnimator.executeAfterPrepareSurfacesRunnables();

        final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;

        // If we are ready to perform an app transition, check through all of the app tokens to be
        // shown and see if they are ready to go.
        if (mService.mAppTransition.isReady()) {
            // This needs to be split into two expressions, as handleAppTransitionReadyLocked may
            // modify dc.pendingLayoutChanges, which would get lost when writing
            // defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked()
            final int layoutChanges = surfacePlacer.handleAppTransitionReadyLocked();
            defaultDisplay.pendingLayoutChanges |= layoutChanges;
            if (DEBUG_LAYOUT_REPEATS)
                surfacePlacer.debugLayoutRepeats("after handleAppTransitionReadyLocked",
                        defaultDisplay.pendingLayoutChanges);
        }
....

....

 }
ViewRootImpl.scheduleTraversals(-->
mTraversalRunnable-->
ViewRootImpl.performTraversals-->
ViewRootImpl.performDraw--->
ViewRootImpl.pendingDrawFinished---->
ViewRootImpl.reportDrawFinished--->
mWindowSession.finishDrawing(mWindow)--->
Session.finishDrawing---->
WindowManagerService.finishDrawingWindow--->

    void finishDrawingWindow(Session session, IWindow client) {
        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized (mWindowMap) {
                WindowState win = windowForClientLocked(session, client, false);
                if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "finishDrawingWindow: " + win + " mDrawState="
                        + (win != null ? win.mWinAnimator.drawStateToString() : "null"));
                if (win != null && win.mWinAnimator.finishDrawingLocked()) {
                    if ((win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
                        win.getDisplayContent().pendingLayoutChanges |=
                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                    }
                    win.setDisplayLayoutNeeded();
                    mWindowPlacerLocked.requestTraversal();
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

 

<think>好的,用户现在问的是HAS_DRAWN到DRAW_PENDING之间耗时800ms的问题。首先,我需要回顾之前的对话,确保自己理解上下文。用户之前询问过这四个状态的含义,现在可能遇到了性能问题,特别是在这两个状态之间出现了延迟。 用户提到的耗时800ms,这明显超出了正常范围,通常Flutter的渲染流程应该在16ms左右完成一帧。所以问题可能出现在哪里呢?首先,HAS_DRAWN表示组件已经完成首次绘制,而DRAW_PENDING是当组件需要重新绘制但还未安排到下一帧的时候。从HAS_DRAWN到DRAW_PENDING的转换,可能涉及到组件状态变化后的重新绘制请求。 接下来,我需要分析可能的原因。常见的原因包括主线程阻塞、频繁的setState调用、复杂的布局或绘制逻辑,以及资源加载问题。比如,如果主线程被大量计算任务占用,导致无法及时处理绘制请求,就会导致延迟。或者,如果在构建或布局阶段有复杂的计算,比如未优化的列表视图或嵌套过深的组件树,也会增加耗时。 用户可能是在开发过程中遇到了界面卡顿,通过调试工具发现了这个耗时问题。他们可能不太清楚如何定位和解决,所以需要具体的排查步骤和解决方案。例如,建议用户使用性能分析工具,检查是否有耗时的Dart代码,或者查看布局和绘制的耗时情况。 另外,用户可能需要知道如何优化,比如避免不必要的重建、使用const构造函数、分解复杂组件等。同时,异步操作或资源加载如果在主线程进行,也可能导致阻塞,需要检查是否有这类问题。 还要考虑到用户可能对Flutter的内部机制不太熟悉,所以需要用比较易懂的语言解释,并提供实际的代码示例或工具使用方法。例如,推荐使用Flutter DevTools中的性能视图,或者添加调试打印语句来定位耗时操作。 最后,确保回答结构清晰,分点列出可能的原因和解决方案,帮助用户逐步排查问题。同时提醒用户如果提供更多上下文,比如代码片段或具体场景,可以给出更针对性的建议。</think>在 Flutter 渲染流程中,**HAS_DRAWN(已绘制)到 DRAW_PENDING(绘制待处理)之间耗时 800ms** 是一个异常现象,可能表明存在严重的性能问题或逻辑阻塞。以下是详细分析和优化方向: --- ### 一、**现象解释** - **正常情况**:Flutter 的渲染管线应在 **16ms 内完成一帧**(60 FPS)。从 `HAS_DRAWN` 到 `DRAW_PENDING` 的转换通常是瞬时的(<1ms),因为它仅涉及标记状态变更。 - **异常值 800ms**: 表示主线程(Dart Isolate)在完成首次绘制后,**被长时间阻塞**,导致无法及时响应新的绘制请求。 --- ### 二、**可能原因** #### 1. **主线程阻塞** - **典型场景**: - 同步的耗时计算(如大数据处理、复杂 JSON 解析) - 未优化的 `build()` 方法(如嵌套过深的组件树、未使用 `const` 构造函数) - 高频 `setState()` 调用(如动画未节流) - **验证方法**: 使用 Flutter DevTools 的 **CPU Profiler** 检查主线程的调用堆栈,定位耗时函数。 #### 2. **布局/绘制复杂度高** - **典型场景**: - 未使用 `ListView.builder` 或 `GridView.builder` 的长列表 - 过度使用 `Opacity`、`ClipPath` 等昂贵效果 - 未缓存的 `Shader` 或 `CustomPaint` 绘制 - **验证方法**: 在 DevTools 的 **Performance** 面板中,观察 `Layout` 和 `Paint` 阶段的耗时。 #### 3. **资源加载延迟** - **典型场景**: - 同步加载大型图片或字体文件(未用 `async`/`await`) - 未预加载的 `Assets` 或 `NetworkImage` - **验证方法**: 检查 `ImageStream` 的加载状态,或使用 `precacheImage()` 预加载资源。 #### 4. **外部插件或原生代码** - **典型场景**: - 通过 `MethodChannel` 调用的阻塞性原生代码(如文件读写、数据库操作) - 第三方插件未正确实现异步操作 - **验证方法**: 注释相关插件调用,观察耗时是否消失。 --- ### 三、**排查步骤** #### 1. **最小化复现** ```dart void main() { runApp(MaterialApp( home: Scaffold( body: Builder(builder: (context) { // 逐步移除组件,定位具体卡顿位置 return YourWidget(); }), ), )); } ``` #### 2. **性能分析工具** - 运行 `flutter run --profile` - 打开 **Flutter DevTools** → **Performance** 面板 - 捕获 **Timeline** 记录,重点关注以下区间: ![Timeline 示例](https://flutter.cn/docs/perf/rendering/ui-performance) #### 3. **代码级调试** - **标记耗时区间**: ```dart void someMethod() { final start = DateTime.now().millisecondsSinceEpoch; // 疑似耗时逻辑 final end = DateTime.now().millisecondsSinceEpoch; print('耗时: ${end - start}ms'); } ``` - **检查 `build()` 方法**: 使用 `Widget Inspector` 查看组件重建次数(避免冗余重建)。 --- ### 四、**优化方案** #### 1. **主线程优化** - 将耗时计算移至 **Isolate**: ```dart final result = await compute(heavyTask, data); ``` - 使用 `ValueNotifier` + `ValueListenableBuilder` 替代高频 `setState()`。 #### 2. **布局/绘制优化** - 对静态组件使用 `const` 构造函数: ```dart const MyWidget(); // 避免重复构建 ``` - 使用 `RepaintBoundary` 隔离绘制区域: ```dart RepaintBoundary(child: ExpensiveWidget()) ``` #### 3. **资源加载优化** - 预加载图片: ```dart precacheImage(AssetImage('assets/large_image.png'), context); ``` - 使用 `LoadingBuilder` 或 `Placeholder` 异步加载: ```dart Image.network(url, loadingBuilder: (ctx, child, progress) { return progress == null ? child : CircularProgressIndicator(); }); ``` #### 4. **GPU 优化** - 减少图层合成(通过 `debugDumpLayerTree` 检查): ```bash flutter run --dart-define=FLUTTER_DEBUG_DUMP_LAYER_TREE=true ``` - 避免过度使用 `SaveLayer`(如 `BackdropFilter`)。 --- ### 五、**总结** 800ms 的延迟通常由 **主线程阻塞** 或 **过度渲染** 导致。通过分阶段排查(复现 → 分析 → 优化)结合 Flutter 工具链,可精准定位瓶颈。若问题仍未解决,可提供 **最小可复现代码** 或 **Timeline 截图**,进一步分析具体场景。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值