Merge "Fix out-of-order transactions (1/2)" into oc-dr1-dev

am: cadfccbc13

Change-Id: Iccfd0df631abb607370de65e7312e6f625b3f5cc
This commit is contained in:
Jorim Jaggi
2017-08-09 16:16:24 +00:00
committed by android-build-merger
2 changed files with 71 additions and 45 deletions

View File

@@ -33,7 +33,6 @@ import android.view.Choreographer;
import android.view.SurfaceControl;
import android.view.WindowManagerPolicy;
import com.android.internal.view.SurfaceFlingerVsyncChoreographer;
import com.android.server.AnimationThread;
import java.io.PrintWriter;
@@ -134,26 +133,38 @@ public class WindowAnimator {
* sure other threads can make progress if this happens.
*/
private void animate(long frameTimeNs) {
boolean transactionOpen = false;
try {
synchronized (mService.mWindowMap) {
if (!mInitialized) {
return;
}
mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
mAnimating = false;
mAppWindowAnimating = false;
if (DEBUG_WINDOW_TRACE) {
Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
}
synchronized (mService.mWindowMap) {
if (!mInitialized) {
return;
}
if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate");
mService.openSurfaceTransaction();
transactionOpen = true;
SurfaceControl.setAnimationTransaction();
// Schedule next frame already such that back-pressure happens continuously
scheduleAnimation();
}
// Simulate back-pressure by opening and closing an empty animation transaction. This makes
// sure that an animation frame is at least presented once on the screen. We do this outside
// of the regular transaction such that we can avoid holding the window manager lock in case
// we receive back-pressure from SurfaceFlinger. Since closing an animation transaction
// without the window manager locks leads to ordering issues (as the transaction will be
// processed only at the beginning of the next frame which may result in another transaction
// that was executed later in WM side gets executed first on SF side), we don't update any
// Surface properties here such that reordering doesn't cause issues.
mService.executeEmptyAnimationTransaction();
synchronized (mService.mWindowMap) {
mCurrentTime = frameTimeNs / TimeUtils.NANOS_PER_MS;
mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
mAnimating = false;
mAppWindowAnimating = false;
if (DEBUG_WINDOW_TRACE) {
Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
}
if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate");
mService.openSurfaceTransaction();
try {
final AccessibilityController accessibilityController =
mService.mAccessibilityController;
final int numDisplays = mDisplayContentsAnimators.size();
@@ -216,27 +227,20 @@ public class WindowAnimator {
mAnimating |= mService.mDragState.stepAnimationLocked(mCurrentTime);
}
if (mAnimating) {
mService.scheduleAnimationLocked();
if (!mAnimating) {
cancelAnimation();
}
if (mService.mWatermark != null) {
mService.mWatermark.drawIfNeeded();
}
}
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
if (transactionOpen) {
// Do not hold window manager lock while closing the transaction, as this might be
// blocking until the next frame, which can lead to total lock starvation.
mService.closeSurfaceTransaction(false /* withLockHeld */);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
mService.closeSurfaceTransaction();
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
}
}
synchronized (mService.mWindowMap) {
boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
boolean doRequest = false;
if (mBulkUpdateParams != 0) {
@@ -404,6 +408,13 @@ public class WindowAnimator {
}
}
private void cancelAnimation() {
if (mAnimationFrameCallbackScheduled) {
mAnimationFrameCallbackScheduled = false;
mChoreographer.removeFrameCallback(mAnimationFrameCallback);
}
}
private class DisplayContentsAnimator {
ScreenRotationAnimation mScreenRotationAnimation = null;
}

View File

@@ -908,29 +908,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
void closeSurfaceTransaction() {
closeSurfaceTransaction(true /* withLockHeld */);
}
/**
* Closes a surface transaction.
*
* @param withLockHeld Whether to acquire the window manager while doing so. In some cases
* holding the lock my lead to starvation in WM in case closeTransaction
* blocks and we call it repeatedly, like we do for animations.
*/
void closeSurfaceTransaction(boolean withLockHeld) {
void closeSurfaceTransaction() {
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction");
synchronized (mWindowMap) {
if (mRoot.mSurfaceTraceEnabled) {
mRoot.mRemoteEventTrace.closeSurfaceTransaction();
}
if (withLockHeld) {
SurfaceControl.closeTransaction();
}
}
if (!withLockHeld) {
SurfaceControl.closeTransaction();
}
} finally {
@@ -938,6 +925,34 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
/**
* Executes an empty animation transaction without holding the WM lock to simulate
* back-pressure. See {@link WindowAnimator#animate} why this is needed.
*/
void executeEmptyAnimationTransaction() {
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "openSurfaceTransaction");
synchronized (mWindowMap) {
if (mRoot.mSurfaceTraceEnabled) {
mRoot.mRemoteEventTrace.openSurfaceTransaction();
}
SurfaceControl.openTransaction();
SurfaceControl.setAnimationTransaction();
if (mRoot.mSurfaceTraceEnabled) {
mRoot.mRemoteEventTrace.closeSurfaceTransaction();
}
}
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction");
SurfaceControl.closeTransaction();
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
/** Listener to notify activity manager about app transitions. */
final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier
= new WindowManagerInternal.AppTransitionListener() {