存在一个问题:负载指纹响应时间衰退达到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();
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();
}
}
其中等待绘制的界面不为空走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;
}
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");
}
....
}
....
}
一个有锁屏界面按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.performDraw--->pendingDrawFinished---->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);
}
}