From acf2226d5314db8dc591430e080ee075d4d32b72 Mon Sep 17 00:00:00 2001 From: Kirill Nikolaev Date: Fri, 24 Aug 2018 15:06:19 +0200 Subject: [PATCH] Unregister onFrameAvailable callbacks when a TextureEntry is released. Otherwise the callbacks may be called after FlutterNativeView is destroyed and is null. Also defensively check for whether the texture is already released in the callback because the callback may be called from another thread by a stale reference (see the comment). This closes https://github.com/flutter/flutter/issues/20951. --- .../android/io/flutter/view/FlutterView.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index 0acaa6c4e894c..33c8c834742be 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -997,9 +997,19 @@ final class SurfaceTextureRegistryEntry implements TextureRegistry.SurfaceTextur this.surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { @Override public void onFrameAvailable(SurfaceTexture texture) { + if (released) { + // Even though we make sure to unregister the callback before releasing, as of Android O + // SurfaceTexture has a data race when accessing the callback, so the callback may + // still be called by a stale reference after released==true and mNativeView==null. + return; + } nativeMarkTextureFrameAvailable(mNativeView.get(), SurfaceTextureRegistryEntry.this.id); } - }); + }, + // The callback relies on being executed on the UI thread (unsynchronised read of mNativeView + // and also the engine code check for platform thread in Shell::OnPlatformViewMarkTextureFrameAvailable), + // so we explicitly pass a Handler for the current thread. + new Handler()); } @Override @@ -1019,6 +1029,9 @@ public void release() { } released = true; nativeUnregisterTexture(mNativeView.get(), id); + // Otherwise onFrameAvailableListener might be called after mNativeView==null + // (https://github.com/flutter/flutter/issues/20951). See also the check in onFrameAvailable. + surfaceTexture.setOnFrameAvailableListener(null); surfaceTexture.release(); } }