This repository has been archived by the owner on Feb 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[camera]fix a crash related to calling engine api in the background t…
…hread
- Loading branch information
1 parent
6531740
commit fdb1c80
Showing
14 changed files
with
425 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/camera/camera/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
packages/camera/camera/example/ios/RunnerTests/ThreadSafeEventChannelTests.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
@import camera; | ||
@import XCTest; | ||
#import <OCMock/OCMock.h> | ||
|
||
@interface ThreadSafeEventChannelTests : XCTestCase | ||
@end | ||
|
||
@implementation ThreadSafeEventChannelTests { | ||
FLTThreadSafeEventChannel *_channel; | ||
XCTestExpectation *_mainThreadExpectation; | ||
} | ||
|
||
- (void)setUp { | ||
[super setUp]; | ||
id mockEventChannel = OCMClassMock([FlutterEventChannel class]); | ||
|
||
_mainThreadExpectation = | ||
[[XCTestExpectation alloc] initWithDescription:@"invokeMethod must be called in main thread"]; | ||
_channel = [[FLTThreadSafeEventChannel alloc] initWithEventChannel:mockEventChannel]; | ||
|
||
OCMStub([mockEventChannel setStreamHandler:[OCMArg any]]).andDo(^(NSInvocation *invocation) { | ||
if (NSThread.isMainThread) { | ||
[self->_mainThreadExpectation fulfill]; | ||
} | ||
}); | ||
} | ||
|
||
- (void)testSetStreamHandler_shouldStayOnMainThreadIfCalledFromMainThread { | ||
[_channel setStreamHandler:nil]; | ||
[self waitForExpectations:@[ _mainThreadExpectation ] timeout:1]; | ||
} | ||
|
||
- (void)testSetStreamHandler_shouldDispatchToMainThreadIfCalledFromBackgroundThread { | ||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
[self->_channel setStreamHandler:nil]; | ||
}); | ||
[self waitForExpectations:@[ _mainThreadExpectation ] timeout:1]; | ||
} | ||
|
||
@end |
46 changes: 46 additions & 0 deletions
46
packages/camera/camera/example/ios/RunnerTests/ThreadSafeMethodChannelTests.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
@import camera; | ||
@import XCTest; | ||
#import <OCMock/OCMock.h> | ||
|
||
@interface ThreadSafeMethodChannelTests : XCTestCase | ||
@end | ||
|
||
@implementation ThreadSafeMethodChannelTests { | ||
FLTThreadSafeMethodChannel *_channel; | ||
XCTestExpectation *_mainThreadExpectation; | ||
} | ||
|
||
- (void)setUp { | ||
[super setUp]; | ||
id mockMethodChannel = OCMClassMock([FlutterMethodChannel class]); | ||
|
||
_mainThreadExpectation = | ||
[[XCTestExpectation alloc] initWithDescription:@"invokeMethod must be called in main thread"]; | ||
_channel = [[FLTThreadSafeMethodChannel alloc] initWithMethodChannel:mockMethodChannel]; | ||
|
||
OCMStub([mockMethodChannel invokeMethod:[OCMArg any] arguments:[OCMArg any]]) | ||
.andDo(^(NSInvocation *invocation) { | ||
if (NSThread.isMainThread) { | ||
[self->_mainThreadExpectation fulfill]; | ||
} | ||
}); | ||
} | ||
|
||
- (void)testInvokeMethod_shouldStayOnMainThreadIfCalledFromMainThread { | ||
[_channel invokeMethod:@"foo" arguments:nil]; | ||
|
||
[self waitForExpectations:@[ _mainThreadExpectation ] timeout:1]; | ||
} | ||
|
||
- (void)testInvokeMethod__shouldDispatchToMainThreadIfCalledFromBackgroundThread { | ||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
[self->_channel invokeMethod:@"foo" arguments:nil]; | ||
}); | ||
[self waitForExpectations:@[ _mainThreadExpectation ] timeout:1]; | ||
} | ||
|
||
@end |
74 changes: 74 additions & 0 deletions
74
packages/camera/camera/example/ios/RunnerTests/ThreadSafeTextureRegistryTests.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
@import camera; | ||
@import XCTest; | ||
#import <OCMock/OCMock.h> | ||
|
||
@interface ThreadSafeTextureRegistryTests : XCTestCase | ||
@end | ||
|
||
@implementation ThreadSafeTextureRegistryTests { | ||
FLTThreadSafeTextureRegistry *_registry; | ||
XCTestExpectation *_registerTextureExpectation; | ||
XCTestExpectation *_unregisterTextureExpectation; | ||
XCTestExpectation *_textureFrameAvailableExpectation; | ||
} | ||
|
||
- (void)setUp { | ||
[super setUp]; | ||
id mockTextureRegistry = OCMProtocolMock(@protocol(FlutterTextureRegistry)); | ||
_registry = [[FLTThreadSafeTextureRegistry alloc] initWithTextureRegistry:mockTextureRegistry]; | ||
|
||
_registerTextureExpectation = [[XCTestExpectation alloc] | ||
initWithDescription:@"registerTexture must be called in main thread"]; | ||
_unregisterTextureExpectation = [[XCTestExpectation alloc] | ||
initWithDescription:@"unregisterTexture must be called in main thread"]; | ||
_textureFrameAvailableExpectation = [[XCTestExpectation alloc] | ||
initWithDescription:@"textureFrameAvailable must be called in main thread"]; | ||
|
||
OCMStub([mockTextureRegistry registerTexture:[OCMArg any]]).andDo(^(NSInvocation *invocation) { | ||
if (NSThread.isMainThread) { | ||
[self->_registerTextureExpectation fulfill]; | ||
} | ||
}); | ||
|
||
OCMStub([mockTextureRegistry unregisterTexture:0]).andDo(^(NSInvocation *invocation) { | ||
if (NSThread.isMainThread) { | ||
[self->_unregisterTextureExpectation fulfill]; | ||
} | ||
}); | ||
|
||
OCMStub([mockTextureRegistry textureFrameAvailable:0]).andDo(^(NSInvocation *invocation) { | ||
if (NSThread.isMainThread) { | ||
[self->_textureFrameAvailableExpectation fulfill]; | ||
} | ||
}); | ||
} | ||
|
||
- (void)testShouldStayOnMainThreadIfCalledFromMainThread { | ||
NSObject<FlutterTexture> *anyTexture = OCMProtocolMock(@protocol(FlutterTexture)); | ||
[_registry registerTextureSync:anyTexture]; | ||
[_registry textureFrameAvailable:0]; | ||
[_registry unregisterTexture:0]; | ||
[self waitForExpectations:@[ | ||
_registerTextureExpectation, _unregisterTextureExpectation, _textureFrameAvailableExpectation | ||
] | ||
timeout:1]; | ||
} | ||
|
||
- (void)testShouldDispatchToMainThreadIfCalledFromBackgroundThread { | ||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | ||
NSObject<FlutterTexture> *anyTexture = OCMProtocolMock(@protocol(FlutterTexture)); | ||
[self->_registry registerTextureSync:anyTexture]; | ||
[self->_registry textureFrameAvailable:0]; | ||
[self->_registry unregisterTexture:0]; | ||
}); | ||
[self waitForExpectations:@[ | ||
_registerTextureExpectation, _unregisterTextureExpectation, _textureFrameAvailableExpectation | ||
] | ||
timeout:1]; | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
packages/camera/camera/ios/Classes/FLTThreadSafeEventChannel.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#import <Flutter/Flutter.h> | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
/** | ||
* Wrapper for FlutterEventChannel that always sends events on the main thread | ||
*/ | ||
@interface FLTThreadSafeEventChannel : NSObject | ||
|
||
/** | ||
* Creates a FLTThreadSafeEventChannel by wrapping a FlutterEventChannel object. | ||
* @param channel The FlutterEventChannel object to be wrapped. | ||
*/ | ||
- (instancetype)initWithEventChannel:(FlutterEventChannel *)channel; | ||
|
||
/* | ||
* Registers a handler for stream setup requests from the Flutter side on main thread. | ||
*/ | ||
- (void)setStreamHandler:(nullable NSObject<FlutterStreamHandler> *)handler; | ||
|
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
29 changes: 29 additions & 0 deletions
29
packages/camera/camera/ios/Classes/FLTThreadSafeEventChannel.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#import "FLTThreadSafeEventChannel.h" | ||
|
||
@implementation FLTThreadSafeEventChannel { | ||
FlutterEventChannel *_channel; | ||
} | ||
|
||
- (instancetype)initWithEventChannel:(FlutterEventChannel *)channel { | ||
self = [super init]; | ||
if (self) { | ||
_channel = channel; | ||
} | ||
return self; | ||
} | ||
|
||
- (void)setStreamHandler:(NSObject<FlutterStreamHandler> *)handler { | ||
if (!NSThread.isMainThread) { | ||
dispatch_async(dispatch_get_main_queue(), ^{ | ||
[self->_channel setStreamHandler:handler]; | ||
}); | ||
} else { | ||
[_channel setStreamHandler:handler]; | ||
} | ||
} | ||
|
||
@end |
Oops, something went wrong.