diff options
10 files changed, 103 insertions, 32 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index ce7eae39931a..5672ef32c00a 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3643,6 +3643,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (mPendingRelaunchCount > 0) { mPendingRelaunchCount--; + if (mPendingRelaunchCount == 0 && !isClientVisible()) { + // Don't count if the client won't report drawn. + mRelaunchStartTime = 0; + } } else { // Update keyguard flags upon finishing relaunch. checkKeyguardFlagsChanged(); diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java index 4355b3855bb7..2a8ac39ead8d 100644 --- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java +++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java @@ -20,9 +20,11 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE; import android.annotation.NonNull; import android.util.ArraySet; +import android.util.Slog; import android.util.SparseArray; import android.view.SurfaceControl; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; /** @@ -65,6 +67,7 @@ class BLASTSyncEngine { class SyncGroup { final int mSyncId; final TransactionReadyListener mListener; + final Runnable mOnTimeout; boolean mReady = false; final ArraySet<WindowContainer> mRootMembers = new ArraySet<>(); private SurfaceControl.Transaction mOrphanTransaction = null; @@ -72,6 +75,12 @@ class BLASTSyncEngine { private SyncGroup(TransactionReadyListener listener, int id) { mSyncId = id; mListener = listener; + mOnTimeout = () -> { + Slog.w(TAG, "Sync group " + mSyncId + " timeout"); + synchronized (mWm.mGlobalLock) { + onTimeout(); + } + }; } /** @@ -114,6 +123,7 @@ class BLASTSyncEngine { } mListener.onTransactionReady(mSyncId, merged); mActiveSyncs.remove(mSyncId); + mWm.mH.removeCallbacks(mOnTimeout); } private void setReady(boolean ready) { @@ -136,6 +146,17 @@ class BLASTSyncEngine { void onCancelSync(WindowContainer wc) { mRootMembers.remove(wc); } + + private void onTimeout() { + if (!mActiveSyncs.contains(mSyncId)) return; + for (int i = mRootMembers.size() - 1; i >= 0; --i) { + final WindowContainer<?> wc = mRootMembers.valueAt(i); + if (!wc.isSyncFinished()) { + Slog.i(TAG, "Unfinished container: " + wc); + } + } + finishNow(); + } } private final WindowManagerService mWm; @@ -147,13 +168,23 @@ class BLASTSyncEngine { } int startSyncSet(TransactionReadyListener listener) { + return startSyncSet(listener, WindowState.BLAST_TIMEOUT_DURATION); + } + + int startSyncSet(TransactionReadyListener listener, long timeoutMs) { final int id = mNextSyncId++; final SyncGroup s = new SyncGroup(listener, id); mActiveSyncs.put(id, s); ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s", id, listener); + scheduleTimeout(s, timeoutMs); return id; } + @VisibleForTesting + void scheduleTimeout(SyncGroup s, long timeoutMs) { + mWm.mH.postDelayed(s.mOnTimeout, timeoutMs); + } + void addToSyncSet(int id, WindowContainer wc) { mActiveSyncs.get(id).addToSync(wc); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 0ecee6641509..0de3fa3ad968 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3449,7 +3449,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @Override public String toString() { - return "Display " + mDisplayId + " info=" + mDisplayInfo + " rootTasks=" + mChildren; + return "Display{#" + mDisplayId + " state=" + Display.stateToString(mDisplayInfo.state) + + " size=" + mDisplayInfo.logicalWidth + "x" + mDisplayInfo.logicalHeight + + " " + Surface.rotationToString(mDisplayInfo.rotation) + "}"; } String getName() { diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 9fc45b972e91..5d82553ad284 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -165,13 +165,13 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe private boolean mNavBarAttachedToApp = false; private int mRecentsDisplayId = INVALID_DISPLAY; - Transition(@TransitionType int type, @TransitionFlags int flags, + Transition(@TransitionType int type, @TransitionFlags int flags, long timeoutMs, TransitionController controller, BLASTSyncEngine syncEngine) { mType = type; mFlags = flags; mController = controller; mSyncEngine = syncEngine; - mSyncId = mSyncEngine.startSyncSet(this); + mSyncId = mSyncEngine.startSyncSet(this, timeoutMs); } void addFlag(int flag) { diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index bf4cf5f75e36..91825ccf98e7 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_IS_RECENTS; import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY; @@ -55,6 +56,11 @@ import java.util.function.LongConsumer; class TransitionController { private static final String TAG = "TransitionController"; + /** The same as legacy APP_TRANSITION_TIMEOUT_MS. */ + private static final int DEFAULT_TIMEOUT_MS = 5000; + /** Less duration for CHANGE type because it does not involve app startup. */ + private static final int CHANGE_TIMEOUT_MS = 2000; + // State constants to line-up with legacy app-transition proto expectations. private static final int LEGACY_STATE_IDLE = 0; private static final int LEGACY_STATE_READY = 1; @@ -121,7 +127,10 @@ class TransitionController { if (mCollectingTransition != null) { throw new IllegalStateException("Simultaneous transitions not supported yet."); } - mCollectingTransition = new Transition(type, flags, this, mAtm.mWindowManager.mSyncEngine); + // Distinguish change type because the response time is usually expected to be not too long. + final long timeoutMs = type == TRANSIT_CHANGE ? CHANGE_TIMEOUT_MS : DEFAULT_TIMEOUT_MS; + mCollectingTransition = new Transition(type, flags, timeoutMs, this, + mAtm.mWindowManager.mSyncEngine); ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Creating Transition: %s", mCollectingTransition); dispatchLegacyAppTransitionPending(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index fd0f4636ec1f..9b53d3e00a1e 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -5396,6 +5396,7 @@ public class WindowManagerService extends IWindowManager.Stub case WINDOW_STATE_BLAST_SYNC_TIMEOUT: { synchronized (mGlobalLock) { final WindowState ws = (WindowState) msg.obj; + Slog.i(TAG, "Blast sync timeout: " + ws); ws.immediatelyNotifyBlastSync(); } break; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 2410d7ec13c2..8fafc7d64c29 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -6041,10 +6041,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // in WAITING state rather than READY. mSyncState = SYNC_STATE_WAITING_FOR_DRAW; requestRedrawForSync(); - - mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this); - mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this, - BLAST_TIMEOUT_DURATION); return true; } diff --git a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java index 7bac3e7b8679..420ea8e63562 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java @@ -62,7 +62,7 @@ public class SyncEngineTests extends WindowTestsBase { public void testTrivialSyncCallback() { TestWindowContainer mockWC = new TestWindowContainer(mWm, false /* waiter */); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -90,7 +90,7 @@ public class SyncEngineTests extends WindowTestsBase { public void testWaitingSyncCallback() { TestWindowContainer mockWC = new TestWindowContainer(mWm, true /* waiter */); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -114,7 +114,7 @@ public class SyncEngineTests extends WindowTestsBase { public void testInvisibleSyncCallback() { TestWindowContainer mockWC = new TestWindowContainer(mWm, true /* waiter */); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -142,7 +142,7 @@ public class SyncEngineTests extends WindowTestsBase { parentWC.addChild(childWC, POSITION_TOP); parentWC.addChild(childWC2, POSITION_TOP); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -175,7 +175,7 @@ public class SyncEngineTests extends WindowTestsBase { TestWindowContainer childWC = new TestWindowContainer(mWm, true /* waiter */); parentWC.addChild(childWC, POSITION_TOP); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -206,7 +206,7 @@ public class SyncEngineTests extends WindowTestsBase { parentWC.addChild(topChildWC, POSITION_TOP); parentWC.addChild(botChildWC, POSITION_BOTTOM); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -238,7 +238,7 @@ public class SyncEngineTests extends WindowTestsBase { parentWC.addChild(topChildWC, POSITION_TOP); parentWC.addChild(botChildWC, POSITION_BOTTOM); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -273,7 +273,7 @@ public class SyncEngineTests extends WindowTestsBase { parentWC.addChild(topChildWC, POSITION_TOP); nonMemberParentWC.addChild(botChildWC, POSITION_BOTTOM); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); @@ -312,7 +312,7 @@ public class SyncEngineTests extends WindowTestsBase { parentWC.addChild(topChildWC, POSITION_TOP); parentWC.addChild(botChildWC, POSITION_BOTTOM); - BLASTSyncEngine bse = new BLASTSyncEngine(mWm); + final BLASTSyncEngine bse = createTestBLASTSyncEngine(); BLASTSyncEngine.TransactionReadyListener listener = mock( BLASTSyncEngine.TransactionReadyListener.class); 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 a1c24c26af35..4e77fa73fd09 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -21,7 +21,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static android.view.WindowManager.TRANSIT_CLOSE; -import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; @@ -44,6 +43,7 @@ import android.os.IBinder; import android.platform.test.annotations.Presubmit; import android.util.ArrayMap; import android.util.ArraySet; +import android.view.SurfaceControl; import android.window.ITaskOrganizer; import android.window.ITransitionPlayer; import android.window.TransitionInfo; @@ -53,9 +53,12 @@ import androidx.test.filters.SmallTest; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + /** * Build/Install/Run: - * atest WmTests:TransitionRecordTests + * atest WmTests:TransitionTests */ @SmallTest @Presubmit @@ -64,13 +67,13 @@ public class TransitionTests extends WindowTestsBase { private Transition createTestTransition(int transitType) { TransitionController controller = mock(TransitionController.class); - BLASTSyncEngine sync = new BLASTSyncEngine(mWm); - return new Transition(transitType, 0 /* flags */, controller, sync); + final BLASTSyncEngine sync = createTestBLASTSyncEngine(); + return new Transition(transitType, 0 /* flags */, 0 /* timeoutMs */, controller, sync); } @Test public void testCreateInfo_NewTask() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; ArraySet<WindowContainer> participants = transition.mParticipants; @@ -88,7 +91,7 @@ public class TransitionTests extends WindowTestsBase { closing.mVisibleRequested = false; opening.mVisibleRequested = true; - int transit = TRANSIT_OLD_TASK_OPEN; + final int transit = transition.mType; int flags = 0; // Check basic both tasks participating @@ -127,7 +130,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testCreateInfo_NestedTasks() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; ArraySet<WindowContainer> participants = transition.mParticipants; @@ -152,7 +155,7 @@ public class TransitionTests extends WindowTestsBase { opening.mVisibleRequested = true; opening2.mVisibleRequested = true; - int transit = TRANSIT_OLD_TASK_OPEN; + final int transit = transition.mType; int flags = 0; // Check full promotion from leaf @@ -177,7 +180,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testCreateInfo_DisplayArea() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges; ArraySet<WindowContainer> participants = transition.mParticipants; final Task showTask = createTask(mDisplayContent); @@ -199,7 +202,7 @@ public class TransitionTests extends WindowTestsBase { showing.mVisibleRequested = true; showing2.mVisibleRequested = true; - int transit = TRANSIT_OLD_TASK_OPEN; + final int transit = transition.mType; int flags = 0; // Check promotion to DisplayArea @@ -228,7 +231,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testCreateInfo_existenceChange() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); final Task openTask = createTask(mDisplayContent); final ActivityRecord opening = createActivityRecord(openTask); @@ -258,7 +261,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testCreateInfo_ordering() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); // pick some number with a high enough chance of being out-of-order when added to set. final int taskCount = 6; @@ -294,7 +297,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testCreateInfo_wallpaper() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); // pick some number with a high enough chance of being out-of-order when added to set. final int taskCount = 4; final int showWallpaperTask = 2; @@ -345,7 +348,7 @@ public class TransitionTests extends WindowTestsBase { @Test public void testTargets_noIntermediatesToWallpaper() { - final Transition transition = createTestTransition(TRANSIT_OLD_TASK_OPEN); + final Transition transition = createTestTransition(TRANSIT_OPEN); final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class), true, mDisplayContent, true /* ownerCanManageAppTokens */); @@ -419,7 +422,7 @@ public class TransitionTests extends WindowTestsBase { openInOpen.mVisibleRequested = true; openInChange.mVisibleRequested = true; - int transit = TRANSIT_OLD_TASK_OPEN; + final int transit = transition.mType; int flags = 0; // Check full promotion from leaf @@ -450,6 +453,22 @@ public class TransitionTests extends WindowTestsBase { } @Test + public void testTimeout() { + final TransitionController controller = new TransitionController(mAtm, + mock(TaskSnapshotController.class)); + final BLASTSyncEngine sync = new BLASTSyncEngine(mWm); + final CountDownLatch latch = new CountDownLatch(1); + // When the timeout is reached, it will finish the sync-group and notify transaction ready. + new Transition(TRANSIT_OPEN, 0 /* flags */, 10 /* timeoutMs */, controller, sync) { + @Override + public void onTransactionReady(int syncId, SurfaceControl.Transaction transaction) { + latch.countDown(); + } + }; + assertTrue(awaitInWmLock(() -> latch.await(3, TimeUnit.SECONDS))); + } + + @Test public void testIntermediateVisibility() { final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class); final TransitionController controller = new TransitionController(mAtm, snapshotController); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index b2d4eea4feae..ac61bb15ab06 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -789,6 +789,15 @@ class WindowTestsBase extends SystemServiceTestsBase { }; } + BLASTSyncEngine createTestBLASTSyncEngine() { + return new BLASTSyncEngine(mWm) { + @Override + void scheduleTimeout(SyncGroup s, long timeoutMs) { + // Disable timeout. + } + }; + } + /** * Avoids rotating screen disturbed by some conditions. It is usually used for the default * display that is not the instance of {@link TestDisplayContent} (it bypasses the conditions). |