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
This commit is contained in:
Riddle Hsu
2023-02-07 13:24:49 +00:00
parent f558dd2d16
commit 46ecdc5cb5
3 changed files with 16 additions and 7 deletions

View File

@@ -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 */);

View File

@@ -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);
}

View File

@@ -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",