Signal dream end to overlay in finish().
Originally, the dream service signaled its exit to the overlay when
the window detaches. However, there are other flows where it's possible
for the dream to initiate exiting before this point. In this case, the
teardown will begin and a race condition will exist between signaling
to the overlay and stopping the dream process.
This changelist addresses this by placing the exit signal to the
overlay in finish. Proceeding through finish is deferred until this
signal is sent, ensuring the overlay is always informed.
Fixes: 265920994
Test: atest DreamOverlayTest
Change-Id: I1a07d3839979d37599c1e053d8715340b5c4830c
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index d378886..cbe1ded 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -1050,6 +1050,24 @@
* </p>
*/
public final void finish() {
+ // If there is an active overlay connection, signal that the dream is ending before
+ // continuing. Note that the overlay cannot rely on the unbound state, since another dream
+ // might have bound to it in the meantime.
+ if (mOverlayConnection != null) {
+ mOverlayConnection.addConsumer(overlay -> {
+ try {
+ overlay.endDream();
+ mOverlayConnection.unbind();
+ mOverlayConnection = null;
+ finish();
+ } catch (RemoteException e) {
+ Log.e(mTag, "could not inform overlay of dream end:" + e);
+ }
+ });
+ mOverlayConnection.clearConsumers();
+ return;
+ }
+
if (mDebug) Slog.v(mTag, "finish(): mFinished=" + mFinished);
Activity activity = mActivity;
@@ -1066,10 +1084,6 @@
}
mFinished = true;
- if (mOverlayConnection != null) {
- mOverlayConnection.unbind();
- }
-
if (mDreamToken == null) {
if (mDebug) Slog.v(mTag, "finish() called when not attached.");
stopSelf();
@@ -1389,17 +1403,6 @@
@Override
public void onViewDetachedFromWindow(View v) {
- if (mOverlayConnection != null) {
- mOverlayConnection.addConsumer(overlay -> {
- try {
- overlay.endDream();
- } catch (RemoteException e) {
- Log.e(mTag, "could not inform overlay of dream end:" + e);
- }
- });
- mOverlayConnection.clearConsumers();
- }
-
if (mActivity == null || !mActivity.isChangingConfigurations()) {
// Only stop the dream if the view is not detached by relaunching
// activity for configuration changes. It is important to also clear
@@ -1408,6 +1411,10 @@
mActivity = null;
finish();
}
+
+ if (mOverlayConnection != null && mDreamStartOverlayConsumer != null) {
+ mOverlayConnection.removeConsumer(mDreamStartOverlayConsumer);
+ }
}
});
}