mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Ensure that unregisterTexture is called when forget to call SurfaceTextureEntry.release (flutter/engine#28304)
This commit is contained in:
parent
4ac725f85f
commit
198f96cd09
@ -39,6 +39,7 @@ public class FlutterRenderer implements TextureRegistry {
|
||||
@NonNull private final AtomicLong nextTextureId = new AtomicLong(0L);
|
||||
@Nullable private Surface surface;
|
||||
private boolean isDisplayingFlutterUi = false;
|
||||
private Handler handler = new Handler();
|
||||
|
||||
@NonNull
|
||||
private final FlutterUiDisplayListener flutterUiDisplayListener =
|
||||
@ -168,6 +169,38 @@ public class FlutterRenderer implements TextureRegistry {
|
||||
unregisterTexture(id);
|
||||
released = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if (released) {
|
||||
return;
|
||||
}
|
||||
|
||||
handler.post(new SurfaceTextureFinalizerRunnable(id, flutterJNI));
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final class SurfaceTextureFinalizerRunnable implements Runnable {
|
||||
private final long id;
|
||||
private final FlutterJNI flutterJNI;
|
||||
|
||||
SurfaceTextureFinalizerRunnable(long id, @NonNull FlutterJNI flutterJNI) {
|
||||
this.id = id;
|
||||
this.flutterJNI = flutterJNI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!flutterJNI.isAttached()) {
|
||||
return;
|
||||
}
|
||||
Log.v(TAG, "Releasing a SurfaceTexture (" + id + ").");
|
||||
flutterJNI.unregisterTexture(id);
|
||||
}
|
||||
}
|
||||
// ------ END TextureRegistry IMPLEMENTATION ----
|
||||
|
||||
|
||||
@ -4,9 +4,14 @@ import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.robolectric.Shadows.shadowOf;
|
||||
|
||||
import android.os.Looper;
|
||||
import android.view.Surface;
|
||||
import io.flutter.embedding.engine.FlutterJNI;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -116,4 +121,78 @@ public class FlutterRendererTest {
|
||||
// Verify behavior under test.
|
||||
verify(fakeFlutterJNI, times(0)).markTextureFrameAvailable(eq(entry.id()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itUnregistersTextureWhenSurfaceTextureFinalized() {
|
||||
// Setup the test.
|
||||
FlutterJNI fakeFlutterJNI = mock(FlutterJNI.class);
|
||||
when(fakeFlutterJNI.isAttached()).thenReturn(true);
|
||||
FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI);
|
||||
|
||||
fakeFlutterJNI.detachFromNativeAndReleaseResources();
|
||||
|
||||
FlutterRenderer.SurfaceTextureRegistryEntry entry =
|
||||
(FlutterRenderer.SurfaceTextureRegistryEntry) flutterRenderer.createSurfaceTexture();
|
||||
long id = entry.id();
|
||||
|
||||
flutterRenderer.startRenderingToSurface(fakeSurface);
|
||||
|
||||
// Execute the behavior under test.
|
||||
runFinalization(entry);
|
||||
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
||||
flutterRenderer.stopRenderingToSurface();
|
||||
|
||||
// Verify behavior under test.
|
||||
verify(fakeFlutterJNI, times(1)).unregisterTexture(eq(id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itStopsUnregisteringTextureWhenDetached() {
|
||||
// Setup the test.
|
||||
FlutterJNI fakeFlutterJNI = mock(FlutterJNI.class);
|
||||
when(fakeFlutterJNI.isAttached()).thenReturn(false);
|
||||
FlutterRenderer flutterRenderer = new FlutterRenderer(fakeFlutterJNI);
|
||||
|
||||
fakeFlutterJNI.detachFromNativeAndReleaseResources();
|
||||
|
||||
FlutterRenderer.SurfaceTextureRegistryEntry entry =
|
||||
(FlutterRenderer.SurfaceTextureRegistryEntry) flutterRenderer.createSurfaceTexture();
|
||||
long id = entry.id();
|
||||
|
||||
flutterRenderer.startRenderingToSurface(fakeSurface);
|
||||
|
||||
flutterRenderer.stopRenderingToSurface();
|
||||
|
||||
// Execute the behavior under test.
|
||||
runFinalization(entry);
|
||||
|
||||
shadowOf(Looper.getMainLooper()).idle();
|
||||
|
||||
// Verify behavior under test.
|
||||
verify(fakeFlutterJNI, times(0)).unregisterTexture(eq(id));
|
||||
}
|
||||
|
||||
void runFinalization(FlutterRenderer.SurfaceTextureRegistryEntry entry) {
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
Thread fakeFinalizer =
|
||||
new Thread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
entry.finalize();
|
||||
latch.countDown();
|
||||
} catch (Throwable e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
});
|
||||
fakeFinalizer.start();
|
||||
try {
|
||||
latch.await(5L, TimeUnit.SECONDS);
|
||||
} catch (Throwable e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user