Fix race condition in FlutterSurfaceManager (#27828)
diff --git a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm
index ca70330..054aaa2 100644
--- a/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm
+++ b/shell/platform/darwin/macos/framework/Source/FlutterSurfaceManager.mm
@@ -27,6 +27,7 @@
CGSize _surfaceSize;
FlutterIOSurfaceHolder* _ioSurfaces[kFlutterSurfaceManagerBufferCount];
+ BOOL _frameInProgress;
}
- (instancetype)initWithLayer:(CALayer*)containingLayer contentTransform:(CATransform3D)transform {
@@ -66,23 +67,33 @@
_ioSurfaces[kFlutterSurfaceManagerFrontBuffer]);
[_delegate onSwapBuffers];
- dispatch_async(dispatch_get_main_queue(), ^{
- [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(onIdle) object:nil];
- [self performSelector:@selector(onIdle) withObject:nil afterDelay:kIdleDelay];
- });
+ // performSelector:withObject:afterDelay needs to be performed on RunLoop thread
+ [self performSelectorOnMainThread:@selector(reschedule) withObject:nil waitUntilDone:NO];
+
+ @synchronized(self) {
+ _frameInProgress = NO;
+ }
+}
+
+- (void)reschedule {
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(onIdle) object:nil];
+ [self performSelector:@selector(onIdle) withObject:nil afterDelay:kIdleDelay];
}
- (void)onIdle {
@synchronized(self) {
- // Release the back buffer and notify delegate. The buffer will be restored
- // on demand in ensureBackBuffer
- _ioSurfaces[kFlutterSurfaceManagerBackBuffer] = nil;
- [self.delegate onSurfaceReleased:kFlutterSurfaceManagerBackBuffer];
+ if (!_frameInProgress) {
+ // Release the back buffer and notify delegate. The buffer will be restored
+ // on demand in ensureBackBuffer
+ _ioSurfaces[kFlutterSurfaceManagerBackBuffer] = nil;
+ [self.delegate onSurfaceReleased:kFlutterSurfaceManagerBackBuffer];
+ }
}
}
- (void)ensureBackBuffer {
@synchronized(self) {
+ _frameInProgress = YES;
if (_ioSurfaces[kFlutterSurfaceManagerBackBuffer] == nil) {
// Restore previously released backbuffer
_ioSurfaces[kFlutterSurfaceManagerBackBuffer] = [[FlutterIOSurfaceHolder alloc] init];