From c869ab918e803cf6e68f456f1532ac8f97f8f726 Mon Sep 17 00:00:00 2001 From: John McCutchan Date: Fri, 15 Sep 2023 10:01:43 -0700 Subject: [PATCH] Tighten up ImageReaderPlatformViewRenderTarget code - Fix a missing Image close in an error path. - Ensure we close the Image when the TextureEntry is finalized. - Fix an inconsistency in the maxImages when running on Android < 33. - Wrap acquireLatestImage in a try block and return a null image instead of crashing the application. --- .../hardware_buffer_external_texture.cc | 2 ++ .../engine/renderer/FlutterRenderer.java | 13 ++++++++++++- .../ImageReaderPlatformViewRenderTarget.java | 19 ++++++++++++++----- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/shell/platform/android/hardware_buffer_external_texture.cc b/shell/platform/android/hardware_buffer_external_texture.cc index 13d76e8d871ea..0b5d54a20785a 100644 --- a/shell/platform/android/hardware_buffer_external_texture.cc +++ b/shell/platform/android/hardware_buffer_external_texture.cc @@ -81,6 +81,8 @@ AHardwareBuffer* HardwareBufferExternalTexture::GetLatestHardwareBuffer() { NDKHelpers::AHardwareBuffer_fromHardwareBuffer( env, hardware_buffer_java.obj()); if (latest_hardware_buffer == nullptr) { + jni_facade_->HardwareBufferClose(hardware_buffer_java); + jni_facade_->ImageClose(image_java); return nullptr; } diff --git a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java index f1faeab73e1ef..6a0f3686ec5c9 100644 --- a/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java +++ b/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java @@ -351,11 +351,16 @@ public long id() { } @Override + @TargetApi(19) public void release() { if (released) { return; } released = true; + if (image != null) { + image.close(); + image = null; + } unregisterTexture(id); } @@ -388,12 +393,18 @@ public Image acquireLatestImage() { } @Override + @TargetApi(19) protected void finalize() throws Throwable { try { if (released) { return; } - + if (image != null) { + // Be sure to finalize any cached image. + image.close(); + image = null; + } + released = true; handler.post(new TextureFinalizerRunnable(id, flutterJNI)); } finally { super.finalize(); diff --git a/shell/platform/android/io/flutter/plugin/platform/ImageReaderPlatformViewRenderTarget.java b/shell/platform/android/io/flutter/plugin/platform/ImageReaderPlatformViewRenderTarget.java index 655f7ee3bcc49..937b00c6ae899 100644 --- a/shell/platform/android/io/flutter/plugin/platform/ImageReaderPlatformViewRenderTarget.java +++ b/shell/platform/android/io/flutter/plugin/platform/ImageReaderPlatformViewRenderTarget.java @@ -9,6 +9,7 @@ import android.os.Build; import android.os.Handler; import android.view.Surface; +import io.flutter.Log; import io.flutter.view.TextureRegistry.ImageTextureEntry; @TargetApi(29) @@ -34,7 +35,12 @@ private void closeReader() { new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { - final Image image = reader.acquireLatestImage(); + Image image = null; + try { + image = reader.acquireLatestImage(); + } catch (IllegalStateException e) { + Log.e(TAG, "New image available that could not be acquired: " + e.toString()); + } if (image == null) { return; } @@ -49,10 +55,13 @@ protected ImageReader createImageReader33() { builder.setMaxImages(3); // Use PRIVATE image format so that we can support video decoding. // TODO(johnmccutchan): Should we always use PRIVATE here? It may impact our - // ability to read back texture data. If we don't always want to use it, how do we - // decide when to use it or not? Perhaps PlatformViews can indicate if they may contain + // ability to read back texture data. If we don't always want to use it, how do + // we + // decide when to use it or not? Perhaps PlatformViews can indicate if they may + // contain // DRM'd content. - // I need to investigate how PRIVATE impacts our ability to take screenshots or capture + // I need to investigate how PRIVATE impacts our ability to take screenshots or + // capture // the output of Flutter application. builder.setImageFormat(ImageFormat.PRIVATE); // Hint that consumed images will only be read by GPU. @@ -69,7 +78,7 @@ protected ImageReader createImageReader29() { bufferWidth, bufferHeight, ImageFormat.PRIVATE, - 2, + 3, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE); reader.setOnImageAvailableListener(this.onImageAvailableListener, onImageAvailableHandler); return reader;