From 46ecdc5cb55403a9fb8c319588bad531e72b25cc Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Tue, 7 Feb 2023 13:24:49 +0000 Subject: [PATCH] Avoid getting crashed by slow transition This avoids extreme cases when the device is slow or the load of system/systemui is heavy. SystemUI crashes: 1. OPEN transition T1 2. Swipe up, queued transition T2 3. T1 timed out, moveToPlaying (added to mPlayingTransitions) 4. T2 starts collecting 5. startTransition of T1 (STATE_PLAYING -> STATE_STARTED) 6. finishTransition from RemoteTransitionHandler 7. Got crash by "Can't finish a non-playing transition" (in mPlayingTransitions but with STATE_STARTED) System server crashes: When executing a non-CHANGE transition with a display change, (open an activity and request to change display orientation) if IDisplayChangeWindowCallback#continueDisplayChange is called from remote after transition timeout, the exception "Trying to rotate outside a transition" will throw at display thread. Bug: 265852118 Bug: 261645736 Test: Set break point at WindowOrganizerController#startTransition to simulate the slowness. Launch app, swipe up, rotate. The device still works normally after resuming the break point. Test: CtsWindowManagerDeviceTestCases Change-Id: Ia0d97823886eff1c935a0cd7f6f6ac6abf3659d5 --- .../server/wm/ActivityStartController.java | 15 ++++++++++----- .../com/android/server/wm/DisplayRotation.java | 3 ++- .../java/com/android/server/wm/Transition.java | 5 ++++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index a7883cbd068c6..5e066faf0e90a 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -605,11 +605,16 @@ public class ActivityStartController { final Task task = r.getTask(); mService.deferWindowLayout(); try { - r.mTransitionController.requestStartTransition(transition, - task, remoteTransition, null /* displayChange */); - r.mTransitionController.collect(task); - r.mTransitionController.setTransientLaunch(r, - TaskDisplayArea.getRootTaskAbove(rootTask)); + final TransitionController controller = r.mTransitionController; + if (controller.getTransitionPlayer() != null) { + controller.requestStartTransition(transition, task, remoteTransition, + null /* displayChange */); + controller.collect(task); + controller.setTransientLaunch(r, TaskDisplayArea.getRootTaskAbove(rootTask)); + } else { + // The transition player might be died when executing the queued transition. + transition.abort(); + } task.moveToFront("startExistingRecents"); task.mInResumeTopActivity = true; task.resumeTopActivity(null /* prev */, options, true /* deferPause */); diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 7071aa728230b..c0817250bd146 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -635,7 +635,8 @@ public class DisplayRotation { if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) { if (!mDisplayContent.mTransitionController.isCollecting()) { - throw new IllegalStateException("Trying to rotate outside a transition"); + // The remote may be too slow to response before transition timeout. + Slog.e(TAG, "Trying to continue rotation outside a transition"); } mDisplayContent.mTransitionController.collect(mDisplayContent); } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 04a2761855639..523067dd56e8e 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -418,7 +418,10 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (mState < STATE_COLLECTING) { throw new IllegalStateException("Can't start Transition which isn't collecting."); } else if (mState >= STATE_STARTED) { - Slog.w(TAG, "Transition already started: " + mSyncId); + Slog.w(TAG, "Transition already started id=" + mSyncId + " state=" + mState); + // The transition may be aborted (STATE_ABORT) or timed out (STATE_PLAYING by + // SyncGroup#finishNow), so do not revert the state to STATE_STARTED. + return; } mState = STATE_STARTED; ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Starting Transition %d",