Do not hold WM lock while closing animation transaction
Animation transactions can be blocking, leading to total window manager starvation. Fix this by not holding lock. Test: Double tap recents button, make sure it's always responsive Change-Id: I8e09e04f243d2bfc09fb68097846a42e76c7cab5 Fixes: 38192114
This commit is contained in:
@@ -115,8 +115,8 @@ public class WindowAnimator {
|
|||||||
mAnimationTick = () -> {
|
mAnimationTick = () -> {
|
||||||
synchronized (mService.mWindowMap) {
|
synchronized (mService.mWindowMap) {
|
||||||
mAnimationTickScheduled = false;
|
mAnimationTickScheduled = false;
|
||||||
animateLocked(mCurrentFrameTime);
|
|
||||||
}
|
}
|
||||||
|
animate(mCurrentFrameTime);
|
||||||
};
|
};
|
||||||
mAnimationFrameCallback = frameTimeNs -> {
|
mAnimationFrameCallback = frameTimeNs -> {
|
||||||
synchronized (mService.mWindowMap) {
|
synchronized (mService.mWindowMap) {
|
||||||
@@ -126,8 +126,8 @@ public class WindowAnimator {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mAnimationTickScheduled = true;
|
mAnimationTickScheduled = true;
|
||||||
mSfChoreographer.scheduleAtSfVsync(mAnimationTick);
|
|
||||||
}
|
}
|
||||||
|
mSfChoreographer.scheduleAtSfVsync(mAnimationTick);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,142 +151,158 @@ public class WindowAnimator {
|
|||||||
mDisplayContentsAnimators.delete(displayId);
|
mDisplayContentsAnimators.delete(displayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Locked on mService.mWindowMap. */
|
/**
|
||||||
private void animateLocked(long frameTimeNs) {
|
* DO NOT HOLD THE WINDOW MANAGER LOCK WHILE CALLING THIS METHOD. Reason: the method closes
|
||||||
if (!mInitialized) {
|
* an animation transaction, that might be blocking until the next sf-vsync, so we want to make
|
||||||
return;
|
* sure other threads can make progress if this happens.
|
||||||
}
|
*/
|
||||||
|
private void animate(long frameTimeNs) {
|
||||||
mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
|
boolean transactionOpen = false;
|
||||||
mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
|
boolean wasAnimating = false;
|
||||||
boolean wasAnimating = mAnimating;
|
|
||||||
setAnimating(false);
|
|
||||||
mAppWindowAnimating = false;
|
|
||||||
if (DEBUG_WINDOW_TRACE) {
|
|
||||||
Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animateLocked");
|
|
||||||
mService.openSurfaceTransaction();
|
|
||||||
SurfaceControl.setAnimationTransaction();
|
|
||||||
try {
|
try {
|
||||||
final AccessibilityController accessibilityController =
|
synchronized (mService.mWindowMap) {
|
||||||
mService.mAccessibilityController;
|
if (!mInitialized) {
|
||||||
final int numDisplays = mDisplayContentsAnimators.size();
|
return;
|
||||||
for (int i = 0; i < numDisplays; i++) {
|
}
|
||||||
final int displayId = mDisplayContentsAnimators.keyAt(i);
|
|
||||||
final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
|
|
||||||
dc.stepAppWindowsAnimation(mCurrentTime);
|
|
||||||
DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
|
|
||||||
|
|
||||||
final ScreenRotationAnimation screenRotationAnimation =
|
mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
|
||||||
displayAnimator.mScreenRotationAnimation;
|
mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
|
||||||
if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
|
wasAnimating = mAnimating;
|
||||||
if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
|
setAnimating(false);
|
||||||
setAnimating(true);
|
mAppWindowAnimating = false;
|
||||||
} else {
|
if (DEBUG_WINDOW_TRACE) {
|
||||||
mBulkUpdateParams |= SET_UPDATE_ROTATION;
|
Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
|
||||||
screenRotationAnimation.kill();
|
}
|
||||||
displayAnimator.mScreenRotationAnimation = null;
|
|
||||||
|
|
||||||
//TODO (multidisplay): Accessibility supported only for the default display.
|
if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate");
|
||||||
if (accessibilityController != null && dc.isDefaultDisplay) {
|
mService.openSurfaceTransaction();
|
||||||
// We just finished rotation animation which means we did not announce
|
transactionOpen = true;
|
||||||
// the rotation and waited for it to end, announce now.
|
SurfaceControl.setAnimationTransaction();
|
||||||
accessibilityController.onRotationChangedLocked(
|
|
||||||
mService.getDefaultDisplayContentLocked());
|
final AccessibilityController accessibilityController =
|
||||||
|
mService.mAccessibilityController;
|
||||||
|
final int numDisplays = mDisplayContentsAnimators.size();
|
||||||
|
for (int i = 0; i < numDisplays; i++) {
|
||||||
|
final int displayId = mDisplayContentsAnimators.keyAt(i);
|
||||||
|
final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
|
||||||
|
dc.stepAppWindowsAnimation(mCurrentTime);
|
||||||
|
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.prepareWindowSurfaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < numDisplays; i++) {
|
||||||
|
final int displayId = mDisplayContentsAnimators.keyAt(i);
|
||||||
|
final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
|
||||||
|
|
||||||
|
dc.checkAppWindowsReadyToShow();
|
||||||
|
|
||||||
|
final ScreenRotationAnimation screenRotationAnimation =
|
||||||
|
mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
|
||||||
|
if (screenRotationAnimation != null) {
|
||||||
|
screenRotationAnimation.updateSurfacesInTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
orAnimating(dc.animateDimLayers());
|
||||||
|
orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
|
||||||
|
//TODO (multidisplay): Magnification is supported only for the default display.
|
||||||
|
if (accessibilityController != null && dc.isDefaultDisplay) {
|
||||||
|
accessibilityController.drawMagnifiedRegionBorderIfNeededLocked();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update animations of all applications, including those
|
if (mService.mDragState != null) {
|
||||||
// associated with exiting/removed apps
|
mAnimating |= mService.mDragState.stepAnimationLocked(mCurrentTime);
|
||||||
++mAnimTransactionSequence;
|
|
||||||
dc.updateWindowsForAnimator(this);
|
|
||||||
dc.updateWallpaperForAnimator(this);
|
|
||||||
dc.prepareWindowSurfaces();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < numDisplays; i++) {
|
|
||||||
final int displayId = mDisplayContentsAnimators.keyAt(i);
|
|
||||||
final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
|
|
||||||
|
|
||||||
dc.checkAppWindowsReadyToShow();
|
|
||||||
|
|
||||||
final ScreenRotationAnimation screenRotationAnimation =
|
|
||||||
mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
|
|
||||||
if (screenRotationAnimation != null) {
|
|
||||||
screenRotationAnimation.updateSurfacesInTransaction();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
orAnimating(dc.animateDimLayers());
|
if (mAnimating) {
|
||||||
orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
|
mService.scheduleAnimationLocked();
|
||||||
//TODO (multidisplay): Magnification is supported only for the default display.
|
|
||||||
if (accessibilityController != null && dc.isDefaultDisplay) {
|
|
||||||
accessibilityController.drawMagnifiedRegionBorderIfNeededLocked();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (mService.mDragState != null) {
|
if (mService.mWatermark != null) {
|
||||||
mAnimating |= mService.mDragState.stepAnimationLocked(mCurrentTime);
|
mService.mWatermark.drawIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mAnimating) {
|
|
||||||
mService.scheduleAnimationLocked();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mService.mWatermark != null) {
|
|
||||||
mService.mWatermark.drawIfNeeded();
|
|
||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
|
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
|
||||||
} finally {
|
} finally {
|
||||||
mService.closeSurfaceTransaction();
|
if (transactionOpen) {
|
||||||
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animateLocked");
|
mService.closeSurfaceTransaction();
|
||||||
}
|
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
|
||||||
|
|
||||||
boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
|
|
||||||
boolean doRequest = false;
|
|
||||||
if (mBulkUpdateParams != 0) {
|
|
||||||
doRequest = mService.mRoot.copyAnimToLayoutParams();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasPendingLayoutChanges || doRequest) {
|
|
||||||
mWindowPlacerLocked.requestTraversal();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mAnimating && !wasAnimating) {
|
|
||||||
|
|
||||||
// Usually app transitions but quite a load onto the system already (with all the things
|
|
||||||
// happening in app), so pause task snapshot persisting to not increase the load.
|
|
||||||
mService.mTaskSnapshotController.setPersisterPaused(true);
|
|
||||||
if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
|
|
||||||
Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mAnimating && wasAnimating) {
|
synchronized (mService.mWindowMap) {
|
||||||
mWindowPlacerLocked.requestTraversal();
|
boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
|
||||||
mService.mTaskSnapshotController.setPersisterPaused(false);
|
boolean doRequest = false;
|
||||||
if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
|
if (mBulkUpdateParams != 0) {
|
||||||
Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
|
doRequest = mService.mRoot.copyAnimToLayoutParams();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (mRemoveReplacedWindows) {
|
if (hasPendingLayoutChanges || doRequest) {
|
||||||
mService.mRoot.removeReplacedWindows();
|
mWindowPlacerLocked.requestTraversal();
|
||||||
mRemoveReplacedWindows = false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
mService.stopUsingSavedSurfaceLocked();
|
if (mAnimating && !wasAnimating) {
|
||||||
mService.destroyPreservedSurfaceLocked();
|
|
||||||
mService.mWindowPlacerLocked.destroyPendingSurfaces();
|
|
||||||
|
|
||||||
if (DEBUG_WINDOW_TRACE) {
|
// Usually app transitions but quite a load onto the system already (with all the
|
||||||
Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
|
// things happening in app), so pause task snapshot persisting to not increase the
|
||||||
+ " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
|
// load.
|
||||||
+ " mPendingLayoutChanges(DEFAULT_DISPLAY)="
|
mService.mTaskSnapshotController.setPersisterPaused(true);
|
||||||
+ Integer.toHexString(getPendingLayoutChanges(DEFAULT_DISPLAY)));
|
if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
|
||||||
|
Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mAnimating && wasAnimating) {
|
||||||
|
mWindowPlacerLocked.requestTraversal();
|
||||||
|
mService.mTaskSnapshotController.setPersisterPaused(false);
|
||||||
|
if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
|
||||||
|
Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRemoveReplacedWindows) {
|
||||||
|
mService.mRoot.removeReplacedWindows();
|
||||||
|
mRemoveReplacedWindows = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mService.stopUsingSavedSurfaceLocked();
|
||||||
|
mService.destroyPreservedSurfaceLocked();
|
||||||
|
mService.mWindowPlacerLocked.destroyPendingSurfaces();
|
||||||
|
|
||||||
|
if (DEBUG_WINDOW_TRACE) {
|
||||||
|
Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
|
||||||
|
+ " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
|
||||||
|
+ " mPendingLayoutChanges(DEFAULT_DISPLAY)="
|
||||||
|
+ Integer.toHexString(getPendingLayoutChanges(DEFAULT_DISPLAY)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user