Loading services/core/java/com/android/server/wm/ActivityTaskManagerService.java +4 −0 Original line number Diff line number Diff line Loading @@ -4777,6 +4777,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (DEBUG_ALL && !mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) { Slog.i(TAG, "continueWindowLayout reason=" + mLayoutReasons); } // ClientTransactions is queued during #deferWindowLayout() for performance. // Notify to continue. mLifecycleManager.onLayoutContinued(); } /** Loading services/core/java/com/android/server/wm/ClientLifecycleManager.java +39 −14 Original line number Diff line number Diff line Loading @@ -105,7 +105,7 @@ class ClientLifecycleManager { final ClientTransaction clientTransaction = getOrCreatePendingTransaction(client); clientTransaction.addTransactionItem(transactionItem); onClientTransactionItemScheduledLocked(clientTransaction); onClientTransactionItemScheduled(clientTransaction); } else { // TODO(b/260873529): cleanup after launch. final ClientTransaction clientTransaction = ClientTransaction.obtain(client); Loading Loading @@ -134,7 +134,7 @@ class ClientLifecycleManager { clientTransaction.addTransactionItem(transactionItem); clientTransaction.addTransactionItem(lifecycleItem); onClientTransactionItemScheduledLocked(clientTransaction); onClientTransactionItemScheduled(clientTransaction); } else { // TODO(b/260873529): cleanup after launch. final ClientTransaction clientTransaction = ClientTransaction.obtain(client); Loading @@ -146,6 +146,9 @@ class ClientLifecycleManager { /** Executes all the pending transactions. */ void dispatchPendingTransactions() { if (!Flags.bundleClientTransactionFlag()) { return; } final int size = mPendingTransactions.size(); for (int i = 0; i < size; i++) { final ClientTransaction transaction = mPendingTransactions.valueAt(i); Loading @@ -158,6 +161,20 @@ class ClientLifecycleManager { mPendingTransactions.clear(); } /** * Called to when {@link WindowSurfacePlacer#continueLayout}. * Dispatches all pending transactions unless there is an ongoing/scheduled layout, in which * case the pending transactions will be dispatched in * {@link RootWindowContainer#performSurfacePlacementNoTrace}. */ void onLayoutContinued() { if (shouldDispatchPendingTransactionsImmediately()) { // Dispatch the pending transactions immediately if there is no ongoing/scheduled layout dispatchPendingTransactions(); } } /** Must only be called with WM lock. */ @NonNull private ClientTransaction getOrCreatePendingTransaction(@NonNull IApplicationThread client) { final IBinder clientBinder = client.asBinder(); Loading @@ -173,20 +190,28 @@ class ClientLifecycleManager { } /** Must only be called with WM lock. */ private void onClientTransactionItemScheduledLocked( private void onClientTransactionItemScheduled( @NonNull ClientTransaction clientTransaction) throws RemoteException { // TODO(b/260873529): make sure WindowSurfacePlacer#requestTraversal is called before // ClientTransaction scheduled when needed. if (mWms != null && (mWms.mWindowPlacerLocked.isInLayout() || mWms.mWindowPlacerLocked.isTraversalScheduled())) { // The pending transactions will be dispatched when // RootWindowContainer#performSurfacePlacementNoTrace. return; } if (shouldDispatchPendingTransactionsImmediately()) { // Dispatch the pending transaction immediately. mPendingTransactions.remove(clientTransaction.getClient().asBinder()); scheduleTransaction(clientTransaction); } } /** Must only be called with WM lock. */ private boolean shouldDispatchPendingTransactionsImmediately() { if (mWms == null) { return true; } // Do not dispatch when // 1. Layout deferred. // 2. Layout requested. // 3. Layout in process. // The pending transactions will be dispatched during layout in // RootWindowContainer#performSurfacePlacementNoTrace. return !mWms.mWindowPlacerLocked.isLayoutDeferred() && !mWms.mWindowPlacerLocked.isTraversalScheduled() && !mWms.mWindowPlacerLocked.isInLayout(); } } services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +12 −0 Original line number Diff line number Diff line Loading @@ -1087,4 +1087,16 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { assertTrue(homeActivity.getTask().isFocused()); assertFalse(pinnedTask.isFocused()); } @Test public void testContinueWindowLayout_notifyClientLifecycleManager() { clearInvocations(mClientLifecycleManager); mAtm.deferWindowLayout(); verify(mClientLifecycleManager, never()).onLayoutContinued(); mAtm.continueWindowLayout(); verify(mClientLifecycleManager).onLayoutContinued(); } } services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java +29 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.wm; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; Loading Loading @@ -52,14 +54,12 @@ import org.mockito.MockitoAnnotations; * Build/Install/Run: * atest WmTests:ClientLifecycleManagerTests */ // Suppress GuardedBy warning on unit tests @SuppressWarnings("GuardedBy") @SmallTest @Presubmit public class ClientLifecycleManagerTests { @Rule(order = 0) public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); @Rule(order = 1) public final SystemServicesTestRule mSystemServices = new SystemServicesTestRule(); Loading Loading @@ -225,4 +225,30 @@ public class ClientLifecycleManagerTests { verify(mTransaction).schedule(); verify(mTransaction).recycle(); } @Test public void testLayoutDeferred() throws RemoteException { mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG); spyOn(mWms.mWindowPlacerLocked); doReturn(false).when(mWms.mWindowPlacerLocked).isInLayout(); doReturn(false).when(mWms.mWindowPlacerLocked).isTraversalScheduled(); doReturn(true).when(mWms.mWindowPlacerLocked).isLayoutDeferred(); // Queue transactions during layout deferred. mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mLifecycleItem); verify(mLifecycleManager, never()).scheduleTransaction(any()); // Continue queueing when there are multi-level defer. mLifecycleManager.onLayoutContinued(); verify(mLifecycleManager, never()).scheduleTransaction(any()); // Immediately dispatch when layout continue without ongoing/scheduled layout. doReturn(false).when(mWms.mWindowPlacerLocked).isLayoutDeferred(); mLifecycleManager.onLayoutContinued(); verify(mLifecycleManager).scheduleTransaction(any()); } } Loading
services/core/java/com/android/server/wm/ActivityTaskManagerService.java +4 −0 Original line number Diff line number Diff line Loading @@ -4777,6 +4777,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (DEBUG_ALL && !mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) { Slog.i(TAG, "continueWindowLayout reason=" + mLayoutReasons); } // ClientTransactions is queued during #deferWindowLayout() for performance. // Notify to continue. mLifecycleManager.onLayoutContinued(); } /** Loading
services/core/java/com/android/server/wm/ClientLifecycleManager.java +39 −14 Original line number Diff line number Diff line Loading @@ -105,7 +105,7 @@ class ClientLifecycleManager { final ClientTransaction clientTransaction = getOrCreatePendingTransaction(client); clientTransaction.addTransactionItem(transactionItem); onClientTransactionItemScheduledLocked(clientTransaction); onClientTransactionItemScheduled(clientTransaction); } else { // TODO(b/260873529): cleanup after launch. final ClientTransaction clientTransaction = ClientTransaction.obtain(client); Loading Loading @@ -134,7 +134,7 @@ class ClientLifecycleManager { clientTransaction.addTransactionItem(transactionItem); clientTransaction.addTransactionItem(lifecycleItem); onClientTransactionItemScheduledLocked(clientTransaction); onClientTransactionItemScheduled(clientTransaction); } else { // TODO(b/260873529): cleanup after launch. final ClientTransaction clientTransaction = ClientTransaction.obtain(client); Loading @@ -146,6 +146,9 @@ class ClientLifecycleManager { /** Executes all the pending transactions. */ void dispatchPendingTransactions() { if (!Flags.bundleClientTransactionFlag()) { return; } final int size = mPendingTransactions.size(); for (int i = 0; i < size; i++) { final ClientTransaction transaction = mPendingTransactions.valueAt(i); Loading @@ -158,6 +161,20 @@ class ClientLifecycleManager { mPendingTransactions.clear(); } /** * Called to when {@link WindowSurfacePlacer#continueLayout}. * Dispatches all pending transactions unless there is an ongoing/scheduled layout, in which * case the pending transactions will be dispatched in * {@link RootWindowContainer#performSurfacePlacementNoTrace}. */ void onLayoutContinued() { if (shouldDispatchPendingTransactionsImmediately()) { // Dispatch the pending transactions immediately if there is no ongoing/scheduled layout dispatchPendingTransactions(); } } /** Must only be called with WM lock. */ @NonNull private ClientTransaction getOrCreatePendingTransaction(@NonNull IApplicationThread client) { final IBinder clientBinder = client.asBinder(); Loading @@ -173,20 +190,28 @@ class ClientLifecycleManager { } /** Must only be called with WM lock. */ private void onClientTransactionItemScheduledLocked( private void onClientTransactionItemScheduled( @NonNull ClientTransaction clientTransaction) throws RemoteException { // TODO(b/260873529): make sure WindowSurfacePlacer#requestTraversal is called before // ClientTransaction scheduled when needed. if (mWms != null && (mWms.mWindowPlacerLocked.isInLayout() || mWms.mWindowPlacerLocked.isTraversalScheduled())) { // The pending transactions will be dispatched when // RootWindowContainer#performSurfacePlacementNoTrace. return; } if (shouldDispatchPendingTransactionsImmediately()) { // Dispatch the pending transaction immediately. mPendingTransactions.remove(clientTransaction.getClient().asBinder()); scheduleTransaction(clientTransaction); } } /** Must only be called with WM lock. */ private boolean shouldDispatchPendingTransactionsImmediately() { if (mWms == null) { return true; } // Do not dispatch when // 1. Layout deferred. // 2. Layout requested. // 3. Layout in process. // The pending transactions will be dispatched during layout in // RootWindowContainer#performSurfacePlacementNoTrace. return !mWms.mWindowPlacerLocked.isLayoutDeferred() && !mWms.mWindowPlacerLocked.isTraversalScheduled() && !mWms.mWindowPlacerLocked.isInLayout(); } }
services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +12 −0 Original line number Diff line number Diff line Loading @@ -1087,4 +1087,16 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase { assertTrue(homeActivity.getTask().isFocused()); assertFalse(pinnedTask.isFocused()); } @Test public void testContinueWindowLayout_notifyClientLifecycleManager() { clearInvocations(mClientLifecycleManager); mAtm.deferWindowLayout(); verify(mClientLifecycleManager, never()).onLayoutContinued(); mAtm.continueWindowLayout(); verify(mClientLifecycleManager).onLayoutContinued(); } }
services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java +29 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.wm; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; Loading Loading @@ -52,14 +54,12 @@ import org.mockito.MockitoAnnotations; * Build/Install/Run: * atest WmTests:ClientLifecycleManagerTests */ // Suppress GuardedBy warning on unit tests @SuppressWarnings("GuardedBy") @SmallTest @Presubmit public class ClientLifecycleManagerTests { @Rule(order = 0) public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); @Rule(order = 1) public final SystemServicesTestRule mSystemServices = new SystemServicesTestRule(); Loading Loading @@ -225,4 +225,30 @@ public class ClientLifecycleManagerTests { verify(mTransaction).schedule(); verify(mTransaction).recycle(); } @Test public void testLayoutDeferred() throws RemoteException { mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG); spyOn(mWms.mWindowPlacerLocked); doReturn(false).when(mWms.mWindowPlacerLocked).isInLayout(); doReturn(false).when(mWms.mWindowPlacerLocked).isTraversalScheduled(); doReturn(true).when(mWms.mWindowPlacerLocked).isLayoutDeferred(); // Queue transactions during layout deferred. mLifecycleManager.scheduleTransactionItem(mNonBinderClient, mLifecycleItem); verify(mLifecycleManager, never()).scheduleTransaction(any()); // Continue queueing when there are multi-level defer. mLifecycleManager.onLayoutContinued(); verify(mLifecycleManager, never()).scheduleTransaction(any()); // Immediately dispatch when layout continue without ongoing/scheduled layout. doReturn(false).when(mWms.mWindowPlacerLocked).isLayoutDeferred(); mLifecycleManager.onLayoutContinued(); verify(mLifecycleManager).scheduleTransaction(any()); } }