Skip to content

Commit

Permalink
[macOS,iOS] Expose channel buffers 'resize' and 'overflow' control co… (
Browse files Browse the repository at this point in the history
#44848)

## Description

This PR update the helper function that invokes the control channel 'resize' command (previous implementation relied on a deprecated format). It also adds a similar helper function for the 'overflow' commands exposed by the control channel.

See:

https://github.com/flutter/engine/blob/93e8901490e78c7ba7e319cce4470d9c6478c6dc/lib/ui/channel_buffers.dart#L302-L309

## Related Issue

iOS and macOS implementation for flutter/flutter#132386

Similar implementations:
- Android: #44434
- Linux: #44636

## Tests

Adds two tests.
  • Loading branch information
bleroux authored and harryterkelsen committed Oct 23, 2023
1 parent 926dd89 commit e27aaba
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 7 deletions.
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

0 comments on commit e27aaba

Please sign in to comment.