ViewRootImpl: Fix child lifetime.
As far as I can tell this has always been broken. We've always had
intermittent reports of buffer-queue-abandoned as well (a recent bug
came with some reports from N). During onStop SurfaceView relies on
onWindowVisibilityChanged, to trigger a visibility change. At this
point SurfaceView will emit the SurfaceDestroyed callback in order to
stop the client from further use of the Surface. The contract we've
been using with ViewRootImpl is at any point following
Activity.performStop returning the WindowManager was free to destroy
the Surfaces. This is why in setWindowsStopped we destroy the hardware
resources for the ViewRoot. However we aren't dispatching anything to
the SurfaceView. The WindowManager will send an app visibility
notification, but that would go through the handler. This means by the
time we return from Stop, there is no guarantee that the
onWindowVisibilityChanged callbacks have been invoked at all. It
seemed most sensible to dispatch the visibility callbacks directly. We
also ensure that getHostVisibility will return false after this point,
so that performTraversals will not reverse our visibility request if
it occurs again prior to the window visibility notification from the
WindowManager. We also guard against emitting a second window
visibility changed callback in the traversals. I don't know at this
point what value the window visibility notification provides but I
don't feel excited about removing it in this CL at this point in
the development cycle.
Test: Put Chrome in PiP. Turn screen off. No Crash!
Bug: 36561071
Change-Id: Id1673561b2299d477b2761b3ac6afa14eabbf7fb
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 076b33c..31911cb 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -683,7 +683,8 @@
mTranslator.translateRectInAppWindowToScreen(mScreenRect);
}
- if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
+ if (mSurfaceControl != null
+ && (!isHardwareAccelerated() || !mRtHandlingPositionUpdates)) {
try {
if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
"postion = [%d, %d, %d, %d]", System.identityHashCode(this),
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 58ef0af..4a7b16e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1249,6 +1249,13 @@
mIsAmbientMode = ambient;
}
+ void setWindowVisibility(int visibility) {
+ if (visibility != mAttachInfo.mWindowVisibility) {
+ mAttachInfo.mWindowVisibility = visibility;
+ mView.dispatchWindowVisibilityChanged(visibility);
+ }
+ }
+
void setWindowStopped(boolean stopped) {
if (mStopped != stopped) {
mStopped = stopped;
@@ -1263,6 +1270,7 @@
if (renderer != null) {
renderer.destroyHardwareResources(mView);
}
+ mView.dispatchWindowVisibilityChanged(View.GONE);
}
}
}
@@ -1297,7 +1305,8 @@
}
int getHostVisibility() {
- return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE;
+ return (mAppVisible || mForceDecorViewVisibility) && !mStopped
+ ? mView.getVisibility() : View.GONE;
}
/**
@@ -1654,8 +1663,8 @@
}
if (viewVisibilityChanged) {
- mAttachInfo.mWindowVisibility = viewVisibility;
- host.dispatchWindowVisibilityChanged(viewVisibility);
+ setWindowVisibility(viewVisibility);
+
if (viewUserVisibilityChanged) {
host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
}