diff --git a/engine/src/flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h b/engine/src/flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h index 9b84cd64c71..cdbf140091e 100644 --- a/engine/src/flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h +++ b/engine/src/flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h @@ -143,9 +143,46 @@ FLUTTER_DARWIN_EXPORT * Adjusts the number of messages that will get buffered when sending messages to * channels that aren't fully set up yet. For example, the engine isn't running * yet or the channel's message handler isn't set up on the Dart side yet. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param newSize The number of messages that will get buffered. + */ ++ (void)resizeChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + size:(NSInteger)newSize; + +/** + * Adjusts the number of messages that will get buffered when sending messages to + * channels that aren't fully set up yet. For example, the engine isn't running + * yet or the channel's message handler isn't set up on the Dart side yet. + * + * @param newSize The number of messages that will get buffered. */ - (void)resizeChannelBuffer:(NSInteger)newSize; +/** + * Defines whether the channel should show warning messages when discarding messages + * due to overflow. + * + * @param warns When false, the channel is expected to overflow and warning messages + * will not be shown. + * @param name The channel name. + * @param messenger The binary messenger. + */ ++ (void)setWarnsOnOverflow:(BOOL)warns + forChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger; + +/** + * Defines whether the channel should show warning messages when discarding messages + * due to overflow. + * + * @param warns When false, the channel is expected to overflow and warning messages + * will not be shown. + */ +- (void)setWarnsOnOverflow:(BOOL)warns; + @end /** diff --git a/engine/src/flutter/shell/platform/darwin/common/framework/Source/FlutterChannels.mm b/engine/src/flutter/shell/platform/darwin/common/framework/Source/FlutterChannels.mm index f360144d374..78d5c084042 100644 --- a/engine/src/flutter/shell/platform/darwin/common/framework/Source/FlutterChannels.mm +++ b/engine/src/flutter/shell/platform/darwin/common/framework/Source/FlutterChannels.mm @@ -9,12 +9,41 @@ FLUTTER_ASSERT_ARC #pragma mark - Basic message channel static NSString* const kFlutterChannelBuffersChannel = @"dev.flutter/channel-buffers"; +static NSString* const kResizeMethod = @"resize"; +static NSString* const kOverflowMethod = @"overflow"; static void ResizeChannelBuffer(NSObject* binaryMessenger, NSString* channel, NSInteger newSize) { - NSString* messageString = [NSString stringWithFormat:@"resize\r%@\r%@", channel, @(newSize)]; - NSData* message = [messageString dataUsingEncoding:NSUTF8StringEncoding]; + NSCAssert(newSize >= 0, @"Channel buffer size must be non-negative"); + // Cast newSize to int because the deserialization logic handles only 32 bits values, + // see + // https://github.com/flutter/engine/blob/93e8901490e78c7ba7e319cce4470d9c6478c6dc/lib/ui/channel_buffers.dart#L495. + NSArray* args = @[ channel, @(static_cast(newSize)) ]; + FlutterMethodCall* resizeMethodCall = [FlutterMethodCall methodCallWithMethodName:kResizeMethod + arguments:args]; + NSObject* codec = [FlutterStandardMethodCodec sharedInstance]; + NSData* message = [codec encodeMethodCall:resizeMethodCall]; + [binaryMessenger sendOnChannel:kFlutterChannelBuffersChannel message:message]; +} + +/** + * Defines whether a channel should show warning messages when discarding messages + * due to overflow. + * + * @param binaryMessenger The binary messenger. + * @param channel The channel name. + * @param warns When false, the channel is expected to overflow and warning messages + * will not be shown. + */ +static void SetWarnsOnOverflow(NSObject* binaryMessenger, + NSString* channel, + BOOL warns) { + FlutterMethodCall* overflowMethodCall = + [FlutterMethodCall methodCallWithMethodName:kOverflowMethod + arguments:@[ channel, @(!warns) ]]; + NSObject* codec = [FlutterStandardMethodCodec sharedInstance]; + NSData* message = [codec encodeMethodCall:overflowMethodCall]; [binaryMessenger sendOnChannel:kFlutterChannelBuffersChannel message:message]; } @@ -114,10 +143,26 @@ static FlutterBinaryMessengerConnection SetMessageHandler( _connection = SetMessageHandler(_messenger, _name, messageHandler, _taskQueue); } ++ (void)resizeChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + size:(NSInteger)newSize { + ResizeChannelBuffer(messenger, name, newSize); +} + - (void)resizeChannelBuffer:(NSInteger)newSize { ResizeChannelBuffer(_messenger, _name, newSize); } ++ (void)setWarnsOnOverflow:(BOOL)warns + forChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger { + SetWarnsOnOverflow(messenger, name, warns); +} + +- (void)setWarnsOnOverflow:(BOOL)warns { + SetWarnsOnOverflow(_messenger, _name, warns); +} + @end #pragma mark - Method channel diff --git a/engine/src/flutter/shell/platform/darwin/common/framework/Source/FlutterChannelsTest.m b/engine/src/flutter/shell/platform/darwin/common/framework/Source/FlutterChannelsTest.m index 767c762d864..fef4a1075cc 100644 --- a/engine/src/flutter/shell/platform/darwin/common/framework/Source/FlutterChannelsTest.m +++ b/engine/src/flutter/shell/platform/darwin/common/framework/Source/FlutterChannelsTest.m @@ -147,7 +147,7 @@ FLUTTER_ASSERT_ARC } - (void)testResize { - NSString* channelName = @"foo"; + NSString* channelName = @"flutter/test"; id binaryMessenger = OCMStrictProtocolMock(@protocol(FlutterBinaryMessenger)); id codec = OCMProtocolMock(@protocol(FlutterMethodCodec)); FlutterBasicMessageChannel* channel = @@ -156,11 +156,39 @@ FLUTTER_ASSERT_ARC codec:codec]; XCTAssertNotNil(channel); - NSString* expectedMessageString = - [NSString stringWithFormat:@"resize\r%@\r%@", channelName, @100]; - NSData* expectedMessage = [expectedMessageString dataUsingEncoding:NSUTF8StringEncoding]; + // The expected content was created from the following Dart code: + // MethodCall call = MethodCall('resize', ['flutter/test',3]); + // StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List(); + const unsigned char bytes[] = {7, 6, 114, 101, 115, 105, 122, 101, 12, 2, + 7, 12, 102, 108, 117, 116, 116, 101, 114, 47, + 116, 101, 115, 116, 3, 3, 0, 0, 0}; + NSData* expectedMessage = [NSData dataWithBytes:bytes length:sizeof(bytes)]; + OCMExpect([binaryMessenger sendOnChannel:@"dev.flutter/channel-buffers" message:expectedMessage]); - [channel resizeChannelBuffer:100]; + [channel resizeChannelBuffer:3]; + OCMVerifyAll(binaryMessenger); + [binaryMessenger stopMocking]; +} + +- (bool)testSetWarnsOnOverflow { + NSString* channelName = @"flutter/test"; + id binaryMessenger = OCMStrictProtocolMock(@protocol(FlutterBinaryMessenger)); + id codec = OCMProtocolMock(@protocol(FlutterMethodCodec)); + FlutterBasicMessageChannel* channel = + [[FlutterBasicMessageChannel alloc] initWithName:channelName + binaryMessenger:binaryMessenger + codec:codec]; + XCTAssertNotNil(channel); + + // The expected content was created from the following Dart code: + // MethodCall call = MethodCall('overflow',['flutter/test', true]); + // StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List(); + const unsigned char bytes[] = {7, 8, 111, 118, 101, 114, 102, 108, 111, 119, 12, 2, 7, 12, + 102, 108, 117, 116, 116, 101, 114, 47, 116, 101, 115, 116, 1}; + NSData* expectedMessage = [NSData dataWithBytes:bytes length:sizeof(bytes)]; + + OCMExpect([binaryMessenger sendOnChannel:@"dev.flutter/channel-buffers" message:expectedMessage]); + [channel setWarnsOnOverflow:NO]; OCMVerifyAll(binaryMessenger); [binaryMessenger stopMocking]; }