Loading services/core/java/com/android/server/wm/TransitionController.java +7 −6 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.server.FgThread; import java.util.ArrayList; import java.util.function.Consumer; import java.util.function.LongConsumer; /** Loading Loading @@ -1314,18 +1315,18 @@ class TransitionController { return transit; } /** Returns {@code true} if it started collecting, {@code false} if it was queued. */ boolean startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Runnable applySync) { /** Starts the sync set if there is no pending or active syncs, otherwise enqueue the sync. */ void startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Consumer<Boolean> applySync) { if (!mQueuedTransitions.isEmpty() || mSyncEngine.hasActiveSync()) { // Just add to queue since we already have a queue. mQueuedTransitions.add(new QueuedTransition(syncGroup, (d) -> applySync.run())); mQueuedTransitions.add(new QueuedTransition(syncGroup, (deferred) -> applySync.accept(true /* deferred */))); ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Queueing legacy sync-set: %s", syncGroup.mSyncId); return false; return; } mSyncEngine.startSyncSet(syncGroup); applySync.run(); return true; applySync.accept(false /* deferred */); } interface OnStartCollect { Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +37 −7 Original line number Diff line number Diff line Loading @@ -232,8 +232,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final BLASTSyncEngine.SyncGroup syncGroup = prepareSyncWithOrganizer(callback); final int syncId = syncGroup.mSyncId; if (mTransitionController.isShellTransitionsEnabled()) { mTransitionController.startLegacySyncOrQueue(syncGroup, () -> { applyTransaction(t, syncId, null /*transition*/, caller); mTransitionController.startLegacySyncOrQueue(syncGroup, (deferred) -> { applyTransaction(t, syncId, null /* transition */, caller, deferred); setSyncReady(syncId); }); } else { Loading Loading @@ -304,7 +304,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub (deferred) -> { nextTransition.start(); nextTransition.mLogger.mStartWCT = wct; applyTransaction(wct, -1 /*syncId*/, nextTransition, caller); applyTransaction(wct, -1 /* syncId */, nextTransition, caller, deferred); if (needsSetReady) { nextTransition.setAllReady(); } Loading Loading @@ -456,7 +457,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub transition.abort(); return; } if (applyTransaction(wct, -1 /* syncId */, transition, caller) if (applyTransaction(wct, -1 /* syncId */, transition, caller, deferred) == TRANSACT_EFFECTS_NONE && transition.mParticipants.isEmpty()) { transition.abort(); return; Loading @@ -476,6 +477,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return applyTransaction(t, syncId, transition, caller, null /* finishTransition */); } private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId, @Nullable Transition transition, @NonNull CallerInfo caller, boolean deferred) { if (deferred) { try { return applyTransaction(t, syncId, transition, caller); } catch (RuntimeException e) { // If the transaction is deferred, the caller could be from TransitionController // #tryStartCollectFromQueue that executes on system's worker thread rather than // binder thread. And the operation in the WCT may be outdated that violates the // current state. So catch the exception to avoid crashing the system. Slog.e(TAG, "Failed to execute deferred applyTransaction", e); } return TRANSACT_EFFECTS_NONE; } return applyTransaction(t, syncId, transition, caller); } /** * @param syncId If non-null, this will be a sync-transaction. * @param transition A transition to collect changes into. Loading Loading @@ -838,13 +856,21 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub switch (type) { case HIERARCHY_OP_TYPE_REMOVE_TASK: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); final Task task = wc != null ? wc.asTask() : null; if (wc == null || wc.asTask() == null || !wc.isAttached()) { Slog.e(TAG, "Attempt to remove invalid task: " + wc); break; } final Task task = wc.asTask(); task.remove(true, "Applying remove task Hierarchy Op"); break; } case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); final Task task = wc != null ? wc.asTask() : null; if (wc == null || !wc.isAttached()) { Slog.e(TAG, "Attempt to set launch root to a detached container: " + wc); break; } final Task task = wc.asTask(); if (task == null) { throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc); } else if (task.getTaskDisplayArea() == null) { Loading @@ -858,7 +884,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); final Task task = wc != null ? wc.asTask() : null; if (wc == null || !wc.isAttached()) { Slog.e(TAG, "Attempt to set launch adjacent to a detached container: " + wc); break; } final Task task = wc.asTask(); final boolean clearRoot = hop.getToTop(); if (task == null) { throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc); Loading services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +6 −2 Original line number Diff line number Diff line Loading @@ -2191,8 +2191,11 @@ public class TransitionTests extends WindowTestsBase { BLASTSyncEngine.SyncGroup legacySync = mSyncEngine.prepareSyncSet( mock(BLASTSyncEngine.TransactionReadyListener.class), "test"); final boolean[] applyLegacy = new boolean[]{false}; controller.startLegacySyncOrQueue(legacySync, () -> applyLegacy[0] = true); final boolean[] applyLegacy = new boolean[2]; controller.startLegacySyncOrQueue(legacySync, (deferred) -> { applyLegacy[0] = true; applyLegacy[1] = deferred; }); assertFalse(applyLegacy[0]); waitUntilHandlersIdle(); Loading @@ -2208,6 +2211,7 @@ public class TransitionTests extends WindowTestsBase { assertTrue(transitA.isPlaying()); // legacy sync should start now assertTrue(applyLegacy[0]); assertTrue(applyLegacy[1]); // transitB must wait assertTrue(transitB.isPending()); Loading Loading
services/core/java/com/android/server/wm/TransitionController.java +7 −6 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.server.FgThread; import java.util.ArrayList; import java.util.function.Consumer; import java.util.function.LongConsumer; /** Loading Loading @@ -1314,18 +1315,18 @@ class TransitionController { return transit; } /** Returns {@code true} if it started collecting, {@code false} if it was queued. */ boolean startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Runnable applySync) { /** Starts the sync set if there is no pending or active syncs, otherwise enqueue the sync. */ void startLegacySyncOrQueue(BLASTSyncEngine.SyncGroup syncGroup, Consumer<Boolean> applySync) { if (!mQueuedTransitions.isEmpty() || mSyncEngine.hasActiveSync()) { // Just add to queue since we already have a queue. mQueuedTransitions.add(new QueuedTransition(syncGroup, (d) -> applySync.run())); mQueuedTransitions.add(new QueuedTransition(syncGroup, (deferred) -> applySync.accept(true /* deferred */))); ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS_MIN, "Queueing legacy sync-set: %s", syncGroup.mSyncId); return false; return; } mSyncEngine.startSyncSet(syncGroup); applySync.run(); return true; applySync.accept(false /* deferred */); } interface OnStartCollect { Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +37 −7 Original line number Diff line number Diff line Loading @@ -232,8 +232,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final BLASTSyncEngine.SyncGroup syncGroup = prepareSyncWithOrganizer(callback); final int syncId = syncGroup.mSyncId; if (mTransitionController.isShellTransitionsEnabled()) { mTransitionController.startLegacySyncOrQueue(syncGroup, () -> { applyTransaction(t, syncId, null /*transition*/, caller); mTransitionController.startLegacySyncOrQueue(syncGroup, (deferred) -> { applyTransaction(t, syncId, null /* transition */, caller, deferred); setSyncReady(syncId); }); } else { Loading Loading @@ -304,7 +304,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub (deferred) -> { nextTransition.start(); nextTransition.mLogger.mStartWCT = wct; applyTransaction(wct, -1 /*syncId*/, nextTransition, caller); applyTransaction(wct, -1 /* syncId */, nextTransition, caller, deferred); if (needsSetReady) { nextTransition.setAllReady(); } Loading Loading @@ -456,7 +457,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub transition.abort(); return; } if (applyTransaction(wct, -1 /* syncId */, transition, caller) if (applyTransaction(wct, -1 /* syncId */, transition, caller, deferred) == TRANSACT_EFFECTS_NONE && transition.mParticipants.isEmpty()) { transition.abort(); return; Loading @@ -476,6 +477,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub return applyTransaction(t, syncId, transition, caller, null /* finishTransition */); } private int applyTransaction(@NonNull WindowContainerTransaction t, int syncId, @Nullable Transition transition, @NonNull CallerInfo caller, boolean deferred) { if (deferred) { try { return applyTransaction(t, syncId, transition, caller); } catch (RuntimeException e) { // If the transaction is deferred, the caller could be from TransitionController // #tryStartCollectFromQueue that executes on system's worker thread rather than // binder thread. And the operation in the WCT may be outdated that violates the // current state. So catch the exception to avoid crashing the system. Slog.e(TAG, "Failed to execute deferred applyTransaction", e); } return TRANSACT_EFFECTS_NONE; } return applyTransaction(t, syncId, transition, caller); } /** * @param syncId If non-null, this will be a sync-transaction. * @param transition A transition to collect changes into. Loading Loading @@ -838,13 +856,21 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub switch (type) { case HIERARCHY_OP_TYPE_REMOVE_TASK: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); final Task task = wc != null ? wc.asTask() : null; if (wc == null || wc.asTask() == null || !wc.isAttached()) { Slog.e(TAG, "Attempt to remove invalid task: " + wc); break; } final Task task = wc.asTask(); task.remove(true, "Applying remove task Hierarchy Op"); break; } case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); final Task task = wc != null ? wc.asTask() : null; if (wc == null || !wc.isAttached()) { Slog.e(TAG, "Attempt to set launch root to a detached container: " + wc); break; } final Task task = wc.asTask(); if (task == null) { throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc); } else if (task.getTaskDisplayArea() == null) { Loading @@ -858,7 +884,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } case HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); final Task task = wc != null ? wc.asTask() : null; if (wc == null || !wc.isAttached()) { Slog.e(TAG, "Attempt to set launch adjacent to a detached container: " + wc); break; } final Task task = wc.asTask(); final boolean clearRoot = hop.getToTop(); if (task == null) { throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc); Loading
services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +6 −2 Original line number Diff line number Diff line Loading @@ -2191,8 +2191,11 @@ public class TransitionTests extends WindowTestsBase { BLASTSyncEngine.SyncGroup legacySync = mSyncEngine.prepareSyncSet( mock(BLASTSyncEngine.TransactionReadyListener.class), "test"); final boolean[] applyLegacy = new boolean[]{false}; controller.startLegacySyncOrQueue(legacySync, () -> applyLegacy[0] = true); final boolean[] applyLegacy = new boolean[2]; controller.startLegacySyncOrQueue(legacySync, (deferred) -> { applyLegacy[0] = true; applyLegacy[1] = deferred; }); assertFalse(applyLegacy[0]); waitUntilHandlersIdle(); Loading @@ -2208,6 +2211,7 @@ public class TransitionTests extends WindowTestsBase { assertTrue(transitA.isPlaying()); // legacy sync should start now assertTrue(applyLegacy[0]); assertTrue(applyLegacy[1]); // transitB must wait assertTrue(transitB.isPending()); Loading