Skip to content

Commit

Permalink
[Windows] Expose channel buffers 'resize' and 'overflow' control comm…
Browse files Browse the repository at this point in the history
…ands exposed by the control channel. (flutter#47158)

## Description

This PR adds two helper functions to invoke the 'resize' and 'overflow' commands exposed by the control channel.
See:

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

Implementation based on the discussion from flutter#46998.

## Related Issue

Windows implementation for flutter/flutter#132386

## Tests

Adds 4 tests.
  • Loading branch information
bleroux authored Dec 14, 2023
1 parent caf3327 commit a565cea
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "flutter/shell/platform/common/client_wrapper/include/flutter/binary_messenger.h"
#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h"
#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h"
#include "gtest/gtest.h"

namespace flutter {
Expand All @@ -20,23 +21,34 @@ class TestBinaryMessenger : public BinaryMessenger {
void Send(const std::string& channel,
const uint8_t* message,
const size_t message_size,
BinaryReply reply) const override {}
BinaryReply reply) const override {
send_called_ = true;
int length = static_cast<int>(message_size);
last_message_ =
std::vector<uint8_t>(message, message + length * sizeof(uint8_t));
}

void SetMessageHandler(const std::string& channel,
BinaryMessageHandler handler) override {
last_message_handler_channel_ = channel;
last_message_handler_ = handler;
}

bool send_called() { return send_called_; }

std::string last_message_handler_channel() {
return last_message_handler_channel_;
}

BinaryMessageHandler last_message_handler() { return last_message_handler_; }

std::vector<uint8_t> last_message() { return last_message_; }

private:
mutable bool send_called_ = false;
std::string last_message_handler_channel_;
BinaryMessageHandler last_message_handler_;
mutable std::vector<uint8_t> last_message_;
};

} // namespace
Expand Down Expand Up @@ -86,4 +98,68 @@ TEST(BasicMessageChannelTest, Unregistration) {
EXPECT_EQ(messenger.last_message_handler(), nullptr);
}

// Tests that calling Resize generates the binary message expected by the Dart
// implementation.
TEST(BasicMessageChannelTest, Resize) {
TestBinaryMessenger messenger;
const std::string channel_name("flutter/test");
BasicMessageChannel channel(&messenger, channel_name,
&flutter::StandardMessageCodec::GetInstance());

channel.Resize(3);

// Because the Dart implementation for the control channel implements its own
// custom deserialization logic, this test compares the generated bytes array
// to the expected one (for instance, the deserialization logic expects the
// size parameter of the resize method call to be an uint32).
//
// The expected content was created from the following Dart code:
// MethodCall call = MethodCall('resize', ['flutter/test',3]);
// StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List();
const int expected_message_size = 29;

EXPECT_EQ(messenger.send_called(), true);
EXPECT_EQ(static_cast<int>(messenger.last_message().size()),
expected_message_size);

int expected[expected_message_size] = {
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};
for (int i = 0; i < expected_message_size; i++) {
EXPECT_EQ(messenger.last_message()[i], expected[i]);
}
}

// Tests that calling SetWarnsOnOverflow generates the binary message expected
// by the Dart implementation.
TEST(BasicMessageChannelTest, SetWarnsOnOverflow) {
TestBinaryMessenger messenger;

const std::string channel_name("flutter/test");
BasicMessageChannel channel(&messenger, channel_name,
&flutter::StandardMessageCodec::GetInstance());

channel.SetWarnsOnOverflow(false);

// Because the Dart implementation for the control channel implements its own
// custom deserialization logic, this test compares the generated bytes array
// to the expected one.
//
// The expected content was created from the following Dart code:
// MethodCall call = MethodCall('overflow',['flutter/test', true]);
// StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List();
const int expected_message_size = 27;

EXPECT_EQ(messenger.send_called(), true);
EXPECT_EQ(static_cast<int>(messenger.last_message().size()),
expected_message_size);

int expected[expected_message_size] = {
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};
for (int i = 0; i < expected_message_size; i++) {
EXPECT_EQ(messenger.last_message()[i], expected[i]);
}
}

} // namespace flutter
42 changes: 42 additions & 0 deletions shell/platform/common/client_wrapper/core_implementations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#include "binary_messenger_impl.h"
#include "include/flutter/engine_method_result.h"
#include "include/flutter/method_channel.h"
#include "include/flutter/standard_method_codec.h"
#include "texture_registrar_impl.h"

namespace flutter {
Expand Down Expand Up @@ -164,6 +166,46 @@ void ReplyManager::SendResponseData(const std::vector<uint8_t>* data) {

} // namespace internal

// ========== method_channel.h ==========

namespace {

constexpr char kControlChannelName[] = "dev.flutter/channel-buffers";
constexpr char kResizeMethod[] = "resize";
constexpr char kOverflowMethod[] = "overflow";

} // namespace

namespace internal {

void ResizeChannel(BinaryMessenger* messenger, std::string name, int new_size) {
auto control_channel = std::make_unique<MethodChannel<EncodableValue>>(
messenger, kControlChannelName, &StandardMethodCodec::GetInstance());

// The deserialization logic handles only 32 bits values, see
// https://github.com/flutter/engine/blob/93e8901490e78c7ba7e319cce4470d9c6478c6dc/lib/ui/channel_buffers.dart#L495.
control_channel->InvokeMethod(
kResizeMethod, std::make_unique<EncodableValue>(EncodableList{
EncodableValue(name),
EncodableValue(static_cast<int32_t>(new_size)),
}));
}

void SetChannelWarnsOnOverflow(BinaryMessenger* messenger,
std::string name,
bool warns) {
auto control_channel = std::make_unique<MethodChannel<EncodableValue>>(
messenger, kControlChannelName, &StandardMethodCodec::GetInstance());

control_channel->InvokeMethod(kOverflowMethod,
std::make_unique<EncodableValue>(EncodableList{
EncodableValue(name),
EncodableValue(!warns),
}));
}

} // namespace internal

// ========== texture_registrar_impl.h ==========

TextureRegistrarImpl::TextureRegistrarImpl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,26 @@

namespace flutter {

namespace internal {
// Internal helper functions used by BasicMessageChannel and MethodChannel.

// 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.
void ResizeChannel(BinaryMessenger* messenger, std::string name, int new_size);

// Defines whether the channel should show warning messages when discarding
// messages due to overflow.
//
// When |warns| is false, the channel is expected to overflow and warning
// messages will not be shown.
void SetChannelWarnsOnOverflow(BinaryMessenger* messenger,
std::string name,
bool warns);

} // namespace internal

class EncodableValue;

// A message reply callback.
Expand Down Expand Up @@ -101,6 +121,23 @@ class BasicMessageChannel {
messenger_->SetMessageHandler(name_, std::move(binary_handler));
}

// 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.
void Resize(int new_size) {
internal::ResizeChannel(messenger_, name_, new_size);
}

// Defines whether the channel should show warning messages when discarding
// messages due to overflow.
//
// When |warns| is false, the channel is expected to overflow and warning
// messages will not be shown.
void SetWarnsOnOverflow(bool warns) {
internal::SetChannelWarnsOnOverflow(messenger_, name_, warns);
}

private:
BinaryMessenger* messenger_;
std::string name_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <iostream>
#include <string>

#include "basic_message_channel.h"
#include "binary_messenger.h"
#include "engine_method_result.h"
#include "method_call.h"
Expand Down Expand Up @@ -122,6 +123,23 @@ class MethodChannel {
messenger_->SetMessageHandler(name_, std::move(binary_handler));
}

// 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.
void Resize(int new_size) {
internal::ResizeChannel(messenger_, name_, new_size);
}

// Defines whether the channel should show warning messages when discarding
// messages due to overflow.
//
// When |warns| is false, the channel is expected to overflow and warning
// messages will not be shown.
void SetWarnsOnOverflow(bool warns) {
internal::SetChannelWarnsOnOverflow(messenger_, name_, warns);
}

private:
BinaryMessenger* messenger_;
std::string name_;
Expand Down
66 changes: 66 additions & 0 deletions shell/platform/common/client_wrapper/method_channel_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ class TestBinaryMessenger : public BinaryMessenger {
BinaryReply reply) const override {
send_called_ = true;
last_reply_handler_ = reply;
int length = static_cast<int>(message_size);
last_message_ =
std::vector<uint8_t>(message, message + length * sizeof(uint8_t));
}

void SetMessageHandler(const std::string& channel,
Expand All @@ -42,11 +45,14 @@ class TestBinaryMessenger : public BinaryMessenger {

BinaryMessageHandler last_message_handler() { return last_message_handler_; }

std::vector<uint8_t> last_message() { return last_message_; }

private:
mutable bool send_called_ = false;
mutable BinaryReply last_reply_handler_;
std::string last_message_handler_channel_;
BinaryMessageHandler last_message_handler_;
mutable std::vector<uint8_t> last_message_;
};

} // namespace
Expand Down Expand Up @@ -156,4 +162,64 @@ TEST(MethodChannelTest, InvokeNotImplemented) {
EXPECT_TRUE(received_not_implemented);
}

// Tests that calling Resize generates the binary message expected by the Dart
// implementation.
TEST(MethodChannelTest, Resize) {
TestBinaryMessenger messenger;
const std::string channel_name("flutter/test");
MethodChannel channel(&messenger, channel_name,
&StandardMethodCodec::GetInstance());

channel.Resize(3);

// Because the Dart implementation for the control channel implements its own
// custom deserialization logic, this test compares the generated bytes array
// to the expected one (for instance, the deserialization logic expects the
// size parameter of the resize method call to be an uint32).
//
// The expected content was created from the following Dart code:
// MethodCall call = MethodCall('resize', ['flutter/test',3]);
// StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List();
const int expected_message_size = 29;

EXPECT_EQ(messenger.send_called(), true);
EXPECT_EQ(static_cast<int>(messenger.last_message().size()),
expected_message_size);

int expected[expected_message_size] = {
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};
for (int i = 0; i < expected_message_size; i++) {
EXPECT_EQ(messenger.last_message()[i], expected[i]);
}
}

// Tests that calling SetWarnsOnOverflow generates the binary message expected
// by the Dart implementation.
TEST(MethodChannelTest, SetWarnsOnOverflow) {
TestBinaryMessenger messenger;

const std::string channel_name("flutter/test");
MethodChannel channel(&messenger, channel_name,
&StandardMethodCodec::GetInstance());

channel.SetWarnsOnOverflow(false);

// The expected content was created from the following Dart code:
// MethodCall call = MethodCall('overflow',['flutter/test', true]);
// StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List();
const int expected_message_size = 27;

EXPECT_EQ(messenger.send_called(), true);
EXPECT_EQ(static_cast<int>(messenger.last_message().size()),
expected_message_size);

int expected[expected_message_size] = {
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};
for (int i = 0; i < expected_message_size; i++) {
EXPECT_EQ(messenger.last_message()[i], expected[i]);
}
}

} // namespace flutter

0 comments on commit a565cea

Please sign in to comment.