From 95419ca1c56c7a9884b575c82a83fbfc1767c489 Mon Sep 17 00:00:00 2001 From: Will Date: Mon, 7 Mar 2022 11:29:23 -0800 Subject: [PATCH] Fix a BadTokenException in DreamOverlayService. This exception occurs when adding the DreamOverlayService's DecorView to WindowManager (presumably because the service has already been destroyed). Test: atest DreamOverlayServiceTest Bug: 221872102 Change-Id: I9eb40c518dc24a92ea06949a0701295883c4f150 --- .../systemui/dreams/DreamOverlayService.java | 9 ++++++++ .../dreams/DreamOverlayServiceTest.java | 22 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index ebc766635733d..dfbb0c7c16243 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -65,6 +65,9 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ // A reference to the {@link Window} used to hold the dream overlay. private Window mWindow; + // True if the service has been destroyed. + private boolean mDestroyed; + private final Complication.Host mHost = new Complication.Host() { @Override public void requestExitDream() { @@ -134,6 +137,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ mPreviewComplication.setDreamLabel(null); mStateController.removeComplication(mPreviewComplication); mStateController.setPreviewMode(false); + mDestroyed = true; super.onDestroy(); } @@ -141,6 +145,11 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) { setCurrentState(Lifecycle.State.STARTED); mExecutor.execute(() -> { + if (mDestroyed) { + // The task could still be executed after the service has been destroyed. Bail if + // that is the case. + return; + } mStateController.setShouldShowComplications(shouldShowComplications()); mStateController.setPreviewMode(isPreviewMode()); if (isPreviewMode()) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java index 35fda1392512e..7d7ccb462b3ef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java @@ -19,6 +19,7 @@ package com.android.systemui.dreams; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -222,4 +223,25 @@ public class DreamOverlayServiceTest extends SysuiTestCase { verify(mLifecycleRegistry).setCurrentState(Lifecycle.State.DESTROYED); verify(mStateController).setOverlayActive(false); } + + @Test + public void testDecorViewNotAddedToWindowAfterDestroy() throws Exception { + when(mDreamOverlayContainerView.getParent()) + .thenReturn(mDreamOverlayContainerViewParent) + .thenReturn(null); + + final IBinder proxy = mService.onBind(new Intent()); + final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy); + + // Inform the overlay service of dream starting. + overlay.startDream(mWindowParams, mDreamOverlayCallback); + + // Destroy the service. + mService.onDestroy(); + + // Run executor tasks. + mMainExecutor.runAllReady(); + + verify(mWindowManager, never()).addView(any(), any()); + } }