diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 9f46f3fc75b04..22e68a3b909cb 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -71,6 +71,7 @@ public class Surface implements Parcelable { private static native long nativeGetNextFrameNumber(long nativeObject); private static native int nativeSetScalingMode(long nativeObject, int scalingMode); private static native void nativeSetBuffersTransform(long nativeObject, long transform); + private static native int nativeForceScopedDisconnect(long nativeObject); public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -550,6 +551,16 @@ public class Surface implements Parcelable { } } + void forceScopedDisconnect() { + synchronized (mLock) { + checkNotReleasedLocked(); + int err = nativeForceScopedDisconnect(mNativeObject); + if (err != 0) { + throw new RuntimeException("Failed to disconnect Surface instance (bad object?)"); + } + } + } + /** * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture * @hide diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 8a16d63fa511f..754cdd8fc02f3 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -587,6 +587,18 @@ public class SurfaceView extends View { for (SurfaceHolder.Callback c : callbacks) { c.surfaceDestroyed(mSurfaceHolder); } + // Since Android N the same surface may be reused and given to us + // again by the system server at a later point. However + // as we didn't do this in previous releases, clients weren't + // necessarily required to clean up properly in + // surfaceDestroyed. This leads to problems for example when + // clients don't destroy their EGL context, and try + // and create a new one on the same surface following reuse. + // Since there is no valid use of the surface in-between + // surfaceDestroyed and surfaceCreated, we force a disconnect, + // so the next connect will always work if we end up reusing + // the surface. + mSurface.forceScopedDisconnect(); } } diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 21e4d2fb229fb..a0c62c3662850 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -487,6 +487,11 @@ static jint nativeSetScalingMode(JNIEnv *env, jclass clazz, jlong nativeObject, return surface->setScalingMode(scalingMode); } +static jint nativeForceScopedDisconnect(JNIEnv *env, jclass clazz, jlong nativeObject) { + Surface* surface = reinterpret_cast(nativeObject); + return surface->disconnect(-1, IGraphicBufferProducer::DisconnectMode::AllLocal); +} + namespace uirenderer { using namespace android::uirenderer::renderthread; @@ -564,6 +569,7 @@ static const JNINativeMethod gSurfaceMethods[] = { {"nativeGetHeight", "(J)I", (void*)nativeGetHeight }, {"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber }, {"nativeSetScalingMode", "(JI)I", (void*)nativeSetScalingMode }, + {"nativeForceScopedDisconnect", "(J)I", (void*)nativeForceScopedDisconnect}, // HWUI context {"nHwuiCreate", "(JJ)J", (void*) hwui::create },