Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 709d0693 authored by Darrell Shi's avatar Darrell Shi Committed by Android (Google) Code Review
Browse files

Merge "Improve DreamOverlayService thread safety." into tm-qpr-dev

parents 0c09d849 0931cd36
Loading
Loading
Loading
Loading
+32 −21
Original line number Diff line number Diff line
@@ -90,13 +90,15 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
            new KeyguardUpdateMonitorCallback() {
                @Override
                public void onShadeExpandedChanged(boolean expanded) {
                    if (mLifecycleRegistry.getCurrentState() != Lifecycle.State.RESUMED
                            && mLifecycleRegistry.getCurrentState() != Lifecycle.State.STARTED) {
                    mExecutor.execute(() -> {
                        if (getCurrentStateLocked() != Lifecycle.State.RESUMED
                                && getCurrentStateLocked() != Lifecycle.State.STARTED) {
                            return;
                        }

                    mLifecycleRegistry.setCurrentState(
                        setCurrentStateLocked(
                                expanded ? Lifecycle.State.STARTED : Lifecycle.State.RESUMED);
                    });
                }
            };

@@ -146,29 +148,30 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
                () -> mExecutor.execute(DreamOverlayService.this::requestExit);
        mDreamOverlayComponent = dreamOverlayComponentFactory.create(viewModelStore, host);
        mLifecycleRegistry = mDreamOverlayComponent.getLifecycleRegistry();
        setCurrentState(Lifecycle.State.CREATED);
    }

    private void setCurrentState(Lifecycle.State state) {
        mExecutor.execute(() -> mLifecycleRegistry.setCurrentState(state));
        mExecutor.execute(() -> setCurrentStateLocked(Lifecycle.State.CREATED));
    }

    @Override
    public void onDestroy() {
        mKeyguardUpdateMonitor.removeCallback(mKeyguardCallback);
        setCurrentState(Lifecycle.State.DESTROYED);

        resetCurrentDreamOverlay();
        mExecutor.execute(() -> {
            setCurrentStateLocked(Lifecycle.State.DESTROYED);

            resetCurrentDreamOverlayLocked();

            mDestroyed = true;
        });

        super.onDestroy();
    }

    @Override
    public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
        setCurrentState(Lifecycle.State.STARTED);

        mExecutor.execute(() -> {
            setCurrentStateLocked(Lifecycle.State.STARTED);

            mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_ENTER_START);

            if (mDestroyed) {
@@ -181,7 +184,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
                // Reset the current dream overlay before starting a new one. This can happen
                // when two dreams overlap (briefly, for a smoother dream transition) and both
                // dreams are bound to the dream overlay service.
                resetCurrentDreamOverlay();
                resetCurrentDreamOverlayLocked();
            }

            mDreamOverlayContainerViewController =
@@ -191,7 +194,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ

            mStateController.setShouldShowComplications(shouldShowComplications());
            addOverlayWindowLocked(layoutParams);
            setCurrentState(Lifecycle.State.RESUMED);
            setCurrentStateLocked(Lifecycle.State.RESUMED);
            mStateController.setOverlayActive(true);
            final ComponentName dreamComponent = getDreamComponent();
            mStateController.setLowLightActive(
@@ -202,6 +205,14 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
        });
    }

    private Lifecycle.State getCurrentStateLocked() {
        return mLifecycleRegistry.getCurrentState();
    }

    private void setCurrentStateLocked(Lifecycle.State state) {
        mLifecycleRegistry.setCurrentState(state);
    }

    /**
     * Inserts {@link Window} to host the dream overlay into the dream's parent window. Must be
     * called from the main executing thread. The window attributes closely mirror those that are
@@ -231,13 +242,13 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
        // Make extra sure the container view has been removed from its old parent (otherwise we
        // risk an IllegalStateException in some cases when setting the container view as the
        // window's content view and the container view hasn't been properly removed previously).
        removeContainerViewFromParent();
        removeContainerViewFromParentLocked();
        mWindow.setContentView(mDreamOverlayContainerViewController.getContainerView());

        mWindowManager.addView(mWindow.getDecorView(), mWindow.getAttributes());
    }

    private void removeContainerViewFromParent() {
    private void removeContainerViewFromParentLocked() {
        View containerView = mDreamOverlayContainerViewController.getContainerView();
        if (containerView == null) {
            return;
@@ -250,7 +261,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
        parentView.removeView(containerView);
    }

    private void resetCurrentDreamOverlay() {
    private void resetCurrentDreamOverlayLocked() {
        if (mStarted && mWindow != null) {
            mWindowManager.removeView(mWindow.getDecorView());
        }
+12 −8
Original line number Diff line number Diff line
@@ -274,24 +274,28 @@ public class DreamOverlayServiceTest extends SysuiTestCase {

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

        // Destroy the service.
        mService.onDestroy();
        mMainExecutor.runAllReady();

        // Inform the overlay service of dream starting.
        overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
                false /*shouldShowComplication*/);
        mMainExecutor.runAllReady();

        // Destroy the service.
        mService.onDestroy();
        verify(mWindowManager, never()).addView(any(), any());
    }

        // Run executor tasks.
    @Test
    public void testNeverRemoveDecorViewIfNotAdded() {
        // Service destroyed before dream started.
        mService.onDestroy();
        mMainExecutor.runAllReady();

        verify(mWindowManager, never()).addView(any(), any());
        verify(mWindowManager, never()).removeView(any());
    }

    @Test