From 676b24cf869bf3e4cd9f56c709f03486e7123ba6 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Wed, 18 Jan 2023 11:21:18 +0000 Subject: [PATCH] Defer dispatching task appeared until transition ready So fillTaskInfo and onTaskAppeared will be called only once at the surface placement after transition ready. It can also avoid sending multiple task appeared event by the intermediate state. Then the time to reach ITransitionPlayer#onTransitionReady may be shorter. Bug: 260059642 Test: TransitionTests#testRunningRemoteTransition Test: OpenAppMicrobenchmark with shell transition. Change-Id: I866189c327778f8c1e41de17326257bd1502b9b0 --- .../com/android/server/wm/ActivityRecord.java | 23 ++++++++++++++++--- .../core/java/com/android/server/wm/Task.java | 17 ++++++++++---- .../com/android/server/wm/Transition.java | 11 +++++---- .../android/server/wm/TransitionTests.java | 6 +++++ 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 4f87b1a22f029..90ac1aad6dcdd 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -6578,12 +6578,29 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A updateReportedVisibilityLocked(); } + /** + * Sets whether something has been visible in the task and returns {@code true} if the state + * is changed from invisible to visible. + */ + private boolean setTaskHasBeenVisible() { + final boolean wasTaskVisible = task.getHasBeenVisible(); + if (wasTaskVisible) { + return false; + } + if (inTransition()) { + // The deferring will be canceled until transition is ready so it won't dispatch + // intermediate states to organizer. + task.setDeferTaskAppear(true); + } + task.setHasBeenVisible(true); + return true; + } + void onStartingWindowDrawn() { boolean wasTaskVisible = false; if (task != null) { mSplashScreenStyleSolidColor = true; - wasTaskVisible = task.getHasBeenVisible(); - task.setHasBeenVisible(true); + wasTaskVisible = !setTaskHasBeenVisible(); } // The transition may not be executed if the starting process hasn't attached. But if the @@ -6621,7 +6638,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } finishLaunchTickingLocked(); if (task != null) { - task.setHasBeenVisible(true); + setTaskHasBeenVisible(); } // Clear indicated launch root task because there's no trampoline activity to expect after // the windows are drawn. diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index b7021c8671ca0..a76d8362eaab2 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -4148,21 +4148,28 @@ class Task extends TaskFragment { void setHasBeenVisible(boolean hasBeenVisible) { mHasBeenVisible = hasBeenVisible; - if (hasBeenVisible) { - if (!mDeferTaskAppear) sendTaskAppeared(); - if (!isRootTask()) { - getRootTask().setHasBeenVisible(true); + if (!hasBeenVisible || mDeferTaskAppear) { + return; + } + sendTaskAppeared(); + for (WindowContainer parent = getParent(); parent != null; parent = parent.getParent()) { + final Task parentTask = parent.asTask(); + if (parentTask == null) { + break; } + parentTask.setHasBeenVisible(true); } } + boolean getHasBeenVisible() { return mHasBeenVisible; } void setDeferTaskAppear(boolean deferTaskAppear) { + final boolean wasDeferred = mDeferTaskAppear; mDeferTaskAppear = deferTaskAppear; - if (!mDeferTaskAppear) { + if (wasDeferred && !deferTaskAppear) { sendTaskAppeared(); } } diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index fa483535761b9..4680093d98ecf 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -1142,12 +1142,15 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { private void commitVisibleActivities(SurfaceControl.Transaction transaction) { for (int i = mParticipants.size() - 1; i >= 0; --i) { final ActivityRecord ar = mParticipants.valueAt(i).asActivityRecord(); - if (ar == null || !ar.isVisibleRequested()) { + if (ar == null || ar.getTask() == null) { continue; } - ar.commitVisibility(true /* visible */, false /* performLayout */, - true /* fromTransition */); - ar.commitFinishDrawing(transaction); + if (ar.isVisibleRequested()) { + ar.commitVisibility(true /* visible */, false /* performLayout */, + true /* fromTransition */); + ar.commitFinishDrawing(transaction); + } + ar.getTask().setDeferTaskAppear(false); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 21135e0a80cc6..90181389c772f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -566,6 +566,8 @@ public class TransitionTests extends WindowTestsBase { doReturn(mock(IBinder.class)).when(delegateProc.getThread()).asBinder(); final ActivityRecord app = new ActivityBuilder(mAtm).setCreateTask(true) .setVisible(false).build(); + final Task task = app.getTask(); + task.setTaskOrganizer(mock(ITaskOrganizer.class), true /* skipTaskAppeared */); app.setVisibleRequested(true); final TransitionController controller = app.mTransitionController; final Transition transition = controller.createTransition(TRANSIT_OPEN); @@ -576,7 +578,11 @@ public class TransitionTests extends WindowTestsBase { controller.requestStartTransition(transition, null /* startTask */, remoteTransition, null /* displayChange */); testPlayer.startTransition(); + app.onStartingWindowDrawn(); + // The task appeared event should be deferred until transition ready. + assertFalse(task.taskAppearedReady()); testPlayer.onTransactionReady(app.getSyncTransaction()); + assertTrue(task.taskAppearedReady()); assertTrue(playerProc.isRunningRemoteTransition()); assertTrue(delegateProc.isRunningRemoteTransition()); assertTrue(controller.mRemotePlayer.reportRunning(delegateProc.getThread()));