Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[macOS,iOS] Expose channel buffers 'resize' and 'overflow' control co… #44848

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions shell/platform/darwin/common/framework/Headers/FlutterChannels.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<FlutterBinaryMessenger>*)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<FlutterBinaryMessenger>*)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

/**
Expand Down
49 changes: 47 additions & 2 deletions shell/platform/darwin/common/framework/Source/FlutterChannels.mm
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,41 @@
#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<FlutterBinaryMessenger>* 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<int>(newSize)) ];
FlutterMethodCall* resizeMethodCall = [FlutterMethodCall methodCallWithMethodName:kResizeMethod
arguments:args];
NSObject<FlutterMethodCodec>* 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<FlutterBinaryMessenger>* binaryMessenger,
NSString* channel,
BOOL warns) {
FlutterMethodCall* overflowMethodCall =
[FlutterMethodCall methodCallWithMethodName:kOverflowMethod
arguments:@[ channel, @(!warns) ]];
NSObject<FlutterMethodCodec>* codec = [FlutterStandardMethodCodec sharedInstance];
NSData* message = [codec encodeMethodCall:overflowMethodCall];
[binaryMessenger sendOnChannel:kFlutterChannelBuffersChannel message:message];
}

Expand Down Expand Up @@ -114,10 +143,26 @@ - (void)setMessageHandler:(FlutterMessageHandler)handler {
_connection = SetMessageHandler(_messenger, _name, messageHandler, _taskQueue);
}

+ (void)resizeChannelWithName:(NSString*)name
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)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<FlutterBinaryMessenger>*)messenger {
SetWarnsOnOverflow(messenger, name, warns);
}

- (void)setWarnsOnOverflow:(BOOL)warns {
SetWarnsOnOverflow(_messenger, _name, warns);
}

@end

#pragma mark - Method channel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,31 @@ - (void)testCallMethodHandler {
}

- (void)testResize {
NSString* channelName = @"foo";
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('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:3];
OCMVerifyAll(binaryMessenger);
[binaryMessenger stopMocking];
}

- (bool)testSetWarnsOnOverflow {
NSString* channelName = @"flutter/test";
id binaryMessenger = OCMStrictProtocolMock(@protocol(FlutterBinaryMessenger));
id codec = OCMProtocolMock(@protocol(FlutterMethodCodec));
FlutterBasicMessageChannel* channel =
Expand All @@ -156,11 +180,15 @@ - (void)testResize {
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('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 resizeChannelBuffer:100];
[channel setWarnsOnOverflow:NO];
OCMVerifyAll(binaryMessenger);
[binaryMessenger stopMocking];
}
Expand Down