Call finishDrawing and notify when Window is removed or hidden

There are cases where a sync transaction is called on a window that's
going to be removed or hidden. In that case, it will never get a
finishDrawing and possibly not get a prepareSurfaces call. Since we're
not really waiting for anything, we can call finishDrawing and
immediately call notifyBlastSyncTransaction.

This change also moves the blast sync timeout removal into
notifyBlastSyncTransaction in case there's another issue where
finishDrawing is called but not notifyBlastSyncTransaction. The reason
for this is the device can at least go back to a normal state instead of
permanently staying stuck.

Fixes: 159507259
Test: WindowOrganizerTests
Change-Id: If483e3769a98cc100c86893f2132aced5f064fe6
This commit is contained in:
chaviw
2020-06-23 08:11:46 -07:00
parent fe913ac721
commit 355befde24
4 changed files with 21 additions and 18 deletions

View File

@@ -5154,8 +5154,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
case WINDOW_STATE_BLAST_SYNC_TIMEOUT: {
synchronized (mGlobalLock) {
final WindowState ws = (WindowState) msg.obj;
ws.finishDrawing(null);
final WindowState ws = (WindowState) msg.obj;
ws.immediatelyNotifyBlastSync();
}
break;
}

View File

@@ -428,6 +428,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
try {
callback.onTransactionReady(mSyncId, mergedTransaction);
} catch (RemoteException e) {
// If there's an exception when trying to send the mergedTransaction to the client, we
// should immediately apply it here so the transactions aren't lost.
mergedTransaction.apply();
}
mTransactionCallbacksByPendingSyncId.remove(mSyncId);

View File

@@ -2192,7 +2192,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void removeIfPossible() {
super.removeIfPossible();
removeIfPossible(false /*keepVisibleDeadWindow*/);
finishDrawing(null);
immediatelyNotifyBlastSync();
}
private void removeIfPossible(boolean keepVisibleDeadWindow) {
@@ -5806,7 +5806,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// client will not render when visibility is GONE. Therefore, call finishDrawing here to
// prevent system server from blocking on a window that will not draw.
if (viewVisibility == View.GONE && mUsingBLASTSyncTransaction) {
finishDrawing(null);
immediatelyNotifyBlastSync();
}
}
@@ -5844,7 +5844,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mWinAnimator.finishDrawingLocked(postDrawTransaction);
}
mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
if (postDrawTransaction != null) {
mBLASTSyncTransaction.merge(postDrawTransaction);
}
@@ -5853,8 +5852,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mWinAnimator.finishDrawingLocked(null);
}
@VisibleForTesting
void notifyBlastSyncTransaction() {
private void notifyBlastSyncTransaction() {
mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
if (!mNotifyBlastOnSurfacePlacement || mWaitingListener == null) {
mNotifyBlastOnSurfacePlacement = false;
return;
@@ -5877,6 +5877,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mNotifyBlastOnSurfacePlacement = false;
}
void immediatelyNotifyBlastSync() {
finishDrawing(null);
notifyBlastSyncTransaction();
}
private boolean requestResizeForBlastSync() {
return useBLASTSync() && !mResizeForBlastSyncReported;
}

View File

@@ -729,7 +729,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
// We should be rejected from the second sync since we are already
// in one.
assertEquals(false, bse.addToSyncSet(id2, task));
finishAndNotifyDrawing(w);
w.immediatelyNotifyBlastSync();
assertEquals(true, bse.addToSyncSet(id2, task));
bse.setReady(id2);
}
@@ -753,7 +753,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
// Since we have a window we have to wait for it to draw to finish sync.
verify(transactionListener, never())
.onTransactionReady(anyInt(), any());
finishAndNotifyDrawing(w);
w.immediatelyNotifyBlastSync();
verify(transactionListener)
.onTransactionReady(anyInt(), any());
}
@@ -821,14 +821,14 @@ public class WindowOrganizerTests extends WindowTestsBase {
int id = bse.startSyncSet(transactionListener);
assertEquals(true, bse.addToSyncSet(id, task));
bse.setReady(id);
finishAndNotifyDrawing(w);
w.immediatelyNotifyBlastSync();
// Since we have a child window we still shouldn't be done.
verify(transactionListener, never())
.onTransactionReady(anyInt(), any());
reset(transactionListener);
finishAndNotifyDrawing(child);
child.immediatelyNotifyBlastSync();
// Ah finally! Done
verify(transactionListener)
.onTransactionReady(anyInt(), any());
@@ -1002,20 +1002,15 @@ public class WindowOrganizerTests extends WindowTestsBase {
verify(mockCallback, never()).onTransactionReady(anyInt(), any());
assertTrue(w1.useBLASTSync());
assertTrue(w2.useBLASTSync());
finishAndNotifyDrawing(w1);
w1.immediatelyNotifyBlastSync();
// Even though one Window finished drawing, both windows should still be using blast sync
assertTrue(w1.useBLASTSync());
assertTrue(w2.useBLASTSync());
finishAndNotifyDrawing(w2);
w2.immediatelyNotifyBlastSync();
verify(mockCallback).onTransactionReady(anyInt(), any());
assertFalse(w1.useBLASTSync());
assertFalse(w2.useBLASTSync());
}
private void finishAndNotifyDrawing(WindowState ws) {
ws.finishDrawing(null);
ws.notifyBlastSyncTransaction();
}
}