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

This commit is contained in:
Darrell Shi
2022-11-03 16:51:25 +00:00
committed by Android (Google) Code Review
2 changed files with 44 additions and 29 deletions

View File

@@ -90,13 +90,15 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
new KeyguardUpdateMonitorCallback() { new KeyguardUpdateMonitorCallback() {
@Override @Override
public void onShadeExpandedChanged(boolean expanded) { public void onShadeExpandedChanged(boolean expanded) {
if (mLifecycleRegistry.getCurrentState() != Lifecycle.State.RESUMED mExecutor.execute(() -> {
&& mLifecycleRegistry.getCurrentState() != Lifecycle.State.STARTED) { if (getCurrentStateLocked() != Lifecycle.State.RESUMED
&& getCurrentStateLocked() != Lifecycle.State.STARTED) {
return; return;
} }
mLifecycleRegistry.setCurrentState( setCurrentStateLocked(
expanded ? Lifecycle.State.STARTED : Lifecycle.State.RESUMED); expanded ? Lifecycle.State.STARTED : Lifecycle.State.RESUMED);
});
} }
}; };
@@ -146,29 +148,30 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
() -> mExecutor.execute(DreamOverlayService.this::requestExit); () -> mExecutor.execute(DreamOverlayService.this::requestExit);
mDreamOverlayComponent = dreamOverlayComponentFactory.create(viewModelStore, host); mDreamOverlayComponent = dreamOverlayComponentFactory.create(viewModelStore, host);
mLifecycleRegistry = mDreamOverlayComponent.getLifecycleRegistry(); mLifecycleRegistry = mDreamOverlayComponent.getLifecycleRegistry();
setCurrentState(Lifecycle.State.CREATED);
}
private void setCurrentState(Lifecycle.State state) { mExecutor.execute(() -> setCurrentStateLocked(Lifecycle.State.CREATED));
mExecutor.execute(() -> mLifecycleRegistry.setCurrentState(state));
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
mKeyguardUpdateMonitor.removeCallback(mKeyguardCallback); mKeyguardUpdateMonitor.removeCallback(mKeyguardCallback);
setCurrentState(Lifecycle.State.DESTROYED);
resetCurrentDreamOverlay(); mExecutor.execute(() -> {
setCurrentStateLocked(Lifecycle.State.DESTROYED);
resetCurrentDreamOverlayLocked();
mDestroyed = true; mDestroyed = true;
});
super.onDestroy(); super.onDestroy();
} }
@Override @Override
public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) { public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
setCurrentState(Lifecycle.State.STARTED);
mExecutor.execute(() -> { mExecutor.execute(() -> {
setCurrentStateLocked(Lifecycle.State.STARTED);
mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_ENTER_START); mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_ENTER_START);
if (mDestroyed) { 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 // 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 // when two dreams overlap (briefly, for a smoother dream transition) and both
// dreams are bound to the dream overlay service. // dreams are bound to the dream overlay service.
resetCurrentDreamOverlay(); resetCurrentDreamOverlayLocked();
} }
mDreamOverlayContainerViewController = mDreamOverlayContainerViewController =
@@ -191,7 +194,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
mStateController.setShouldShowComplications(shouldShowComplications()); mStateController.setShouldShowComplications(shouldShowComplications());
addOverlayWindowLocked(layoutParams); addOverlayWindowLocked(layoutParams);
setCurrentState(Lifecycle.State.RESUMED); setCurrentStateLocked(Lifecycle.State.RESUMED);
mStateController.setOverlayActive(true); mStateController.setOverlayActive(true);
final ComponentName dreamComponent = getDreamComponent(); final ComponentName dreamComponent = getDreamComponent();
mStateController.setLowLightActive( 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 * 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 * 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 // 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 // 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). // window's content view and the container view hasn't been properly removed previously).
removeContainerViewFromParent(); removeContainerViewFromParentLocked();
mWindow.setContentView(mDreamOverlayContainerViewController.getContainerView()); mWindow.setContentView(mDreamOverlayContainerViewController.getContainerView());
mWindowManager.addView(mWindow.getDecorView(), mWindow.getAttributes()); mWindowManager.addView(mWindow.getDecorView(), mWindow.getAttributes());
} }
private void removeContainerViewFromParent() { private void removeContainerViewFromParentLocked() {
View containerView = mDreamOverlayContainerViewController.getContainerView(); View containerView = mDreamOverlayContainerViewController.getContainerView();
if (containerView == null) { if (containerView == null) {
return; return;
@@ -250,7 +261,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
parentView.removeView(containerView); parentView.removeView(containerView);
} }
private void resetCurrentDreamOverlay() { private void resetCurrentDreamOverlayLocked() {
if (mStarted && mWindow != null) { if (mStarted && mWindow != null) {
mWindowManager.removeView(mWindow.getDecorView()); mWindowManager.removeView(mWindow.getDecorView());
} }

View File

@@ -274,26 +274,30 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
@Test @Test
public void testDecorViewNotAddedToWindowAfterDestroy() throws Exception { public void testDecorViewNotAddedToWindowAfterDestroy() throws Exception {
when(mDreamOverlayContainerView.getParent())
.thenReturn(mDreamOverlayContainerViewParent)
.thenReturn(null);
final IBinder proxy = mService.onBind(new Intent()); final IBinder proxy = mService.onBind(new Intent());
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy); final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
// Destroy the service.
mService.onDestroy();
mMainExecutor.runAllReady();
// Inform the overlay service of dream starting. // Inform the overlay service of dream starting.
overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT, overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
false /*shouldShowComplication*/); false /*shouldShowComplication*/);
// Destroy the service.
mService.onDestroy();
// Run executor tasks.
mMainExecutor.runAllReady(); mMainExecutor.runAllReady();
verify(mWindowManager, never()).addView(any(), any()); verify(mWindowManager, never()).addView(any(), any());
} }
@Test
public void testNeverRemoveDecorViewIfNotAdded() {
// Service destroyed before dream started.
mService.onDestroy();
mMainExecutor.runAllReady();
verify(mWindowManager, never()).removeView(any());
}
@Test @Test
public void testResetCurrentOverlayWhenConnectedToNewDream() throws RemoteException { public void testResetCurrentOverlayWhenConnectedToNewDream() throws RemoteException {
final IBinder proxy = mService.onBind(new Intent()); final IBinder proxy = mService.onBind(new Intent());