diff --git a/core/api/current.txt b/core/api/current.txt index 205be59c0f955..3d5d4c30af9aa 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -60278,7 +60278,7 @@ package android.window { method @UiThread public void remove(); } - public class SurfaceSyncGroup { + public final class SurfaceSyncGroup { ctor public SurfaceSyncGroup(@NonNull String); method @UiThread public boolean add(@Nullable android.view.AttachedSurfaceControl, @Nullable Runnable); method public boolean add(@NonNull android.view.SurfaceControlViewHost.SurfacePackage, @Nullable Runnable); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index de946a4572890..ef824300a314d 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -11428,33 +11428,25 @@ public final class ViewRootImpl implements ViewParent, }); } - private class VRISurfaceSyncGroup extends SurfaceSyncGroup { - VRISurfaceSyncGroup(String name) { - super(name); - } - - @Override - public void onSyncReady() { - Runnable runnable = () -> { - mNumPausedForSync--; - if (!mIsInTraversal && mNumPausedForSync == 0) { - scheduleTraversals(); - } - }; - - if (Thread.currentThread() == mThread) { - runnable.run(); - } else { - mHandler.post(runnable); - } - } - } - @Override public SurfaceSyncGroup getOrCreateSurfaceSyncGroup() { boolean newSyncGroup = false; if (mActiveSurfaceSyncGroup == null) { - mActiveSurfaceSyncGroup = new VRISurfaceSyncGroup(mTag); + mActiveSurfaceSyncGroup = new SurfaceSyncGroup(mTag); + mActiveSurfaceSyncGroup.setAddedToSyncListener(() -> { + Runnable runnable = () -> { + mNumPausedForSync--; + if (!mIsInTraversal && mNumPausedForSync == 0) { + scheduleTraversals(); + } + }; + + if (Thread.currentThread() == mThread) { + runnable.run(); + } else { + mHandler.post(runnable); + } + }); updateSyncInProgressCount(mActiveSurfaceSyncGroup); newSyncGroup = true; } diff --git a/core/java/android/window/SurfaceSyncGroup.java b/core/java/android/window/SurfaceSyncGroup.java index 2e55041d2e8cd..78de9544b59bb 100644 --- a/core/java/android/window/SurfaceSyncGroup.java +++ b/core/java/android/window/SurfaceSyncGroup.java @@ -53,7 +53,7 @@ import java.util.function.Supplier; * see the SurfaceSyncGroup documentation *

*/ -public class SurfaceSyncGroup { +public final class SurfaceSyncGroup { private static final String TAG = "SurfaceSyncGroup"; private static final boolean DEBUG = false; @@ -101,6 +101,9 @@ public class SurfaceSyncGroup { */ public final ISurfaceSyncGroup mISurfaceSyncGroup = new ISurfaceSyncGroupImpl(); + @GuardedBy("mLock") + private Runnable mAddedToSyncListener; + /** * Token to identify this SurfaceSyncGroup. This is used to register the SurfaceSyncGroup in * WindowManager. This token is also sent to other processes' SurfaceSyncGroup that want to be @@ -447,12 +450,15 @@ public class SurfaceSyncGroup { } /** - * Invoked when the SurfaceSyncGroup has been added to another SurfaceSyncGroup and is ready - * to proceed. + * Add a Runnable to be invoked when the SurfaceSyncGroup has been added to another + * SurfaceSyncGroup. This is useful to know when it's safe to proceed rendering. * * @hide */ - public void onSyncReady() { + public void setAddedToSyncListener(Runnable addedToSyncListener) { + synchronized (mLock) { + mAddedToSyncListener = addedToSyncListener; + } } private boolean addSyncToWm(IBinder token, boolean parentSyncGroupMerge, @@ -525,12 +531,15 @@ public class SurfaceSyncGroup { if (DEBUG) { Log.d(TAG, "setTransactionCallbackFromParent " + mName); } - boolean finished = false; + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "setTransactionCallbackFromParent " + mName + " callback=" + transactionReadyCallback.hashCode()); } + + boolean finished = false; + Runnable addedToSyncListener = null; synchronized (mLock) { if (mFinished) { finished = true; @@ -577,6 +586,7 @@ public class SurfaceSyncGroup { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }; + addedToSyncListener = mAddedToSyncListener; } } @@ -587,8 +597,8 @@ public class SurfaceSyncGroup { transactionReadyCallback.onTransactionReady(null); } catch (RemoteException e) { } - } else { - onSyncReady(); + } else if (addedToSyncListener != null) { + addedToSyncListener.run(); } if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.traceEnd(Trace.TRACE_TAG_VIEW); diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java index 22d72ed3d361c..c5387272f0bf8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceSyncGroupTest.java @@ -54,11 +54,11 @@ public class SurfaceSyncGroupTest { final CountDownLatch finishedLatch = new CountDownLatch(1); SurfaceSyncGroup syncGroup = new SurfaceSyncGroup(TAG); syncGroup.addSyncCompleteCallback(mExecutor, finishedLatch::countDown); - SyncTarget syncTarget = new SyncTarget(); + SurfaceSyncGroup syncTarget = new SurfaceSyncGroup("FakeSyncTarget"); syncGroup.add(syncTarget, null /* runnable */); syncGroup.markSyncReady(); - syncTarget.onBufferReady(); + syncTarget.markSyncReady(); finishedLatch.await(5, TimeUnit.SECONDS); assertEquals(0, finishedLatch.getCount()); @@ -69,22 +69,22 @@ public class SurfaceSyncGroupTest { final CountDownLatch finishedLatch = new CountDownLatch(1); SurfaceSyncGroup syncGroup = new SurfaceSyncGroup(TAG); syncGroup.addSyncCompleteCallback(mExecutor, finishedLatch::countDown); - SyncTarget syncTarget1 = new SyncTarget(); - SyncTarget syncTarget2 = new SyncTarget(); - SyncTarget syncTarget3 = new SyncTarget(); + SurfaceSyncGroup syncTarget1 = new SurfaceSyncGroup("FakeSyncTarget1"); + SurfaceSyncGroup syncTarget2 = new SurfaceSyncGroup("FakeSyncTarget2"); + SurfaceSyncGroup syncTarget3 = new SurfaceSyncGroup("FakeSyncTarget3"); syncGroup.add(syncTarget1, null /* runnable */); syncGroup.add(syncTarget2, null /* runnable */); syncGroup.add(syncTarget3, null /* runnable */); syncGroup.markSyncReady(); - syncTarget1.onBufferReady(); + syncTarget1.markSyncReady(); assertNotEquals(0, finishedLatch.getCount()); - syncTarget3.onBufferReady(); + syncTarget3.markSyncReady(); assertNotEquals(0, finishedLatch.getCount()); - syncTarget2.onBufferReady(); + syncTarget2.markSyncReady(); finishedLatch.await(5, TimeUnit.SECONDS); assertEquals(0, finishedLatch.getCount()); @@ -94,8 +94,8 @@ public class SurfaceSyncGroupTest { public void testAddSyncWhenSyncComplete() { SurfaceSyncGroup syncGroup = new SurfaceSyncGroup(TAG); - SyncTarget syncTarget1 = new SyncTarget(); - SyncTarget syncTarget2 = new SyncTarget(); + SurfaceSyncGroup syncTarget1 = new SurfaceSyncGroup("FakeSyncTarget1"); + SurfaceSyncGroup syncTarget2 = new SurfaceSyncGroup("FakeSyncTarget2"); assertTrue(syncGroup.add(syncTarget1, null /* runnable */)); syncGroup.markSyncReady(); @@ -114,21 +114,21 @@ public class SurfaceSyncGroupTest { syncGroup1.addSyncCompleteCallback(mExecutor, finishedLatch1::countDown); syncGroup2.addSyncCompleteCallback(mExecutor, finishedLatch2::countDown); - SyncTarget syncTarget1 = new SyncTarget(); - SyncTarget syncTarget2 = new SyncTarget(); + SurfaceSyncGroup syncTarget1 = new SurfaceSyncGroup("FakeSyncTarget1"); + SurfaceSyncGroup syncTarget2 = new SurfaceSyncGroup("FakeSyncTarget2"); assertTrue(syncGroup1.add(syncTarget1, null /* runnable */)); assertTrue(syncGroup2.add(syncTarget2, null /* runnable */)); syncGroup1.markSyncReady(); syncGroup2.markSyncReady(); - syncTarget1.onBufferReady(); + syncTarget1.markSyncReady(); finishedLatch1.await(5, TimeUnit.SECONDS); assertEquals(0, finishedLatch1.getCount()); assertNotEquals(0, finishedLatch2.getCount()); - syncTarget2.onBufferReady(); + syncTarget2.markSyncReady(); finishedLatch2.await(5, TimeUnit.SECONDS); assertEquals(0, finishedLatch2.getCount()); @@ -144,8 +144,8 @@ public class SurfaceSyncGroupTest { syncGroup1.addSyncCompleteCallback(mExecutor, finishedLatch1::countDown); syncGroup2.addSyncCompleteCallback(mExecutor, finishedLatch2::countDown); - SyncTarget syncTarget1 = new SyncTarget(); - SyncTarget syncTarget2 = new SyncTarget(); + SurfaceSyncGroup syncTarget1 = new SurfaceSyncGroup("FakeSyncTarget1"); + SurfaceSyncGroup syncTarget2 = new SurfaceSyncGroup("FakeSyncTarget2"); assertTrue(syncGroup1.add(syncTarget1, null /* runnable */)); assertTrue(syncGroup2.add(syncTarget2, null /* runnable */)); @@ -155,12 +155,12 @@ public class SurfaceSyncGroupTest { // Finish syncTarget2 first to test that the syncGroup is not complete until the merged sync // is also done. - syncTarget2.onBufferReady(); + syncTarget2.markSyncReady(); finishedLatch2.await(1, TimeUnit.SECONDS); // Sync did not complete yet assertNotEquals(0, finishedLatch2.getCount()); - syncTarget1.onBufferReady(); + syncTarget1.markSyncReady(); // The first sync will still get a callback when it's sync requirements are done. finishedLatch1.await(5, TimeUnit.SECONDS); @@ -180,13 +180,13 @@ public class SurfaceSyncGroupTest { syncGroup1.addSyncCompleteCallback(mExecutor, finishedLatch1::countDown); syncGroup2.addSyncCompleteCallback(mExecutor, finishedLatch2::countDown); - SyncTarget syncTarget1 = new SyncTarget(); - SyncTarget syncTarget2 = new SyncTarget(); + SurfaceSyncGroup syncTarget1 = new SurfaceSyncGroup("FakeSyncTarget1"); + SurfaceSyncGroup syncTarget2 = new SurfaceSyncGroup("FakeSyncTarget2"); assertTrue(syncGroup1.add(syncTarget1, null /* runnable */)); assertTrue(syncGroup2.add(syncTarget2, null /* runnable */)); syncGroup1.markSyncReady(); - syncTarget1.onBufferReady(); + syncTarget1.markSyncReady(); // The first sync will still get a callback when it's sync requirements are done. finishedLatch1.await(5, TimeUnit.SECONDS); @@ -194,7 +194,7 @@ public class SurfaceSyncGroupTest { syncGroup2.add(syncGroup1, null /* runnable */); syncGroup2.markSyncReady(); - syncTarget2.onBufferReady(); + syncTarget2.markSyncReady(); // Verify that the second sync will receive complete since the merged sync was already // completed before the merge. @@ -212,9 +212,9 @@ public class SurfaceSyncGroupTest { syncGroup1.addSyncCompleteCallback(mExecutor, finishedLatch1::countDown); syncGroup2.addSyncCompleteCallback(mExecutor, finishedLatch2::countDown); - SyncTarget syncTarget1 = new SyncTarget(); - SyncTarget syncTarget2 = new SyncTarget(); - SyncTarget syncTarget3 = new SyncTarget(); + SurfaceSyncGroup syncTarget1 = new SurfaceSyncGroup("FakeSyncTarget1"); + SurfaceSyncGroup syncTarget2 = new SurfaceSyncGroup("FakeSyncTarget2"); + SurfaceSyncGroup syncTarget3 = new SurfaceSyncGroup("FakeSyncTarget3"); assertTrue(syncGroup1.add(syncTarget1, null /* runnable */)); assertTrue(syncGroup1.add(syncTarget2, null /* runnable */)); @@ -228,8 +228,8 @@ public class SurfaceSyncGroupTest { // Make target1 and target3 ready, but not target2. SyncGroup2 should not be ready since // SyncGroup2 also waits for all of SyncGroup1 to finish, which includes target2 - syncTarget1.onBufferReady(); - syncTarget3.onBufferReady(); + syncTarget1.markSyncReady(); + syncTarget3.markSyncReady(); // Neither SyncGroup will be ready. finishedLatch1.await(1, TimeUnit.SECONDS); @@ -238,7 +238,7 @@ public class SurfaceSyncGroupTest { assertEquals(1, finishedLatch1.getCount()); assertEquals(1, finishedLatch2.getCount()); - syncTarget2.onBufferReady(); + syncTarget2.markSyncReady(); // Both sync groups should be ready after target2 completed. finishedLatch1.await(5, TimeUnit.SECONDS); @@ -257,13 +257,13 @@ public class SurfaceSyncGroupTest { syncGroup1.addSyncCompleteCallback(mExecutor, finishedLatch1::countDown); syncGroup2.addSyncCompleteCallback(mExecutor, finishedLatch2::countDown); - SyncTarget syncTarget1 = new SyncTarget(); - SyncTarget syncTarget2 = new SyncTarget(); - SyncTarget syncTarget3 = new SyncTarget(); + SurfaceSyncGroup syncTarget1 = new SurfaceSyncGroup("FakeSyncTarget1"); + SurfaceSyncGroup syncTarget2 = new SurfaceSyncGroup("FakeSyncTarget2"); + SurfaceSyncGroup syncTarget3 = new SurfaceSyncGroup("FakeSyncTarget3"); assertTrue(syncGroup1.add(syncTarget1, null /* runnable */)); assertTrue(syncGroup1.add(syncTarget2, null /* runnable */)); - syncTarget2.onBufferReady(); + syncTarget2.markSyncReady(); // Add syncTarget1 to syncGroup2 so it forces syncGroup1 into syncGroup2 assertTrue(syncGroup2.add(syncTarget1, null /* runnable */)); @@ -272,7 +272,7 @@ public class SurfaceSyncGroupTest { syncGroup1.markSyncReady(); syncGroup2.markSyncReady(); - syncTarget1.onBufferReady(); + syncTarget1.markSyncReady(); // Only SyncGroup1 will be ready, but SyncGroup2 still needs its own targets to be ready. finishedLatch1.await(1, TimeUnit.SECONDS); @@ -281,7 +281,7 @@ public class SurfaceSyncGroupTest { assertEquals(0, finishedLatch1.getCount()); assertEquals(1, finishedLatch2.getCount()); - syncTarget3.onBufferReady(); + syncTarget3.markSyncReady(); // SyncGroup2 is finished after target3 completed. finishedLatch2.await(1, TimeUnit.SECONDS); @@ -302,7 +302,7 @@ public class SurfaceSyncGroupTest { SurfaceControl.Transaction targetTransaction = spy(new StubTransaction()); SurfaceSyncGroup.setTransactionFactory(() -> targetTransaction); - SyncTarget syncTarget = new SyncTarget(); + SurfaceSyncGroup syncTarget = new SurfaceSyncGroup("FakeSyncTarget"); assertTrue( syncGroup.add(syncTarget.mISurfaceSyncGroup, true /* parentSyncGroupMerge */, null /* runnable */)); @@ -329,7 +329,7 @@ public class SurfaceSyncGroupTest { SurfaceControl.Transaction targetTransaction = spy(new StubTransaction()); SurfaceSyncGroup.setTransactionFactory(() -> targetTransaction); - SyncTarget syncTarget = new SyncTarget(); + SurfaceSyncGroup syncTarget = new SurfaceSyncGroup("FakeSyncTarget"); assertTrue(syncGroup.add(syncTarget, null /* runnable */)); syncTarget.markSyncReady(); @@ -344,13 +344,13 @@ public class SurfaceSyncGroupTest { final CountDownLatch finishedLatch = new CountDownLatch(1); SurfaceSyncGroup syncGroup = new SurfaceSyncGroup(TAG); syncGroup.addSyncCompleteCallback(mExecutor, finishedLatch::countDown); - SyncTarget syncTarget = new SyncTarget(); + SurfaceSyncGroup syncTarget = new SurfaceSyncGroup("FakeSyncTarget"); syncGroup.add(syncTarget, null /* runnable */); // Add the syncTarget to the same syncGroup and ensure it doesn't crash. syncGroup.add(syncTarget, null /* runnable */); syncGroup.markSyncReady(); - syncTarget.onBufferReady(); + syncTarget.markSyncReady(); try { finishedLatch.await(5, TimeUnit.SECONDS); @@ -359,14 +359,4 @@ public class SurfaceSyncGroupTest { } assertEquals(0, finishedLatch.getCount()); } - - private static class SyncTarget extends SurfaceSyncGroup { - SyncTarget() { - super("FakeSyncTarget"); - } - - void onBufferReady() { - markSyncReady(); - } - } }