SurfaceView: Force surface disconnection before reuse.
Prior to N, if a client received the surfaceDestroyed callback from their SurfaceView they could trust that the surface would not be reused. Now that is not true in multiple scenarios. If a client fails to shut down its EGL context then, we could end up in a situation where, the client will never disconnect. Then when we reuse the same underlying IGraphicBufferProducer for surfaceCreated next the app will crash with a double connect error. There is no valid use of the surface inbetween surfaceDestroyed and surfaceCreated, so we just force the disconnection after surfaceDestroyed. Bug: 30236166 Change-Id: I2e3e4b3176492dc0c2d46a59e0b5a781bf9bc356
This commit is contained in:
@@ -59,6 +59,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<Surface> CREATOR =
|
||||
new Parcelable.Creator<Surface>() {
|
||||
@@ -538,6 +539,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
|
||||
|
||||
@@ -586,6 +586,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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Surface*>(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 },
|
||||
|
||||
Reference in New Issue
Block a user