[Linux] Allow BasicMessageChannel sending and responding to null message (flutter/engine#42808)

## Description

This PR changes how a null message is handled by the Linux engine for a basic message channel.

**Before**:

- when receiving a null message a warning was emitted.
- `fl_binary_messenger_send_response` was called but failed and the application exited.

```
** (bug:9866): WARNING **: 23:13:42.109: Failed to decode message: Unexpected end of data

** (bug:9866): CRITICAL **: 23:13:42.109: gboolean send_response(FlBinaryMessenger *, FlBinaryMessengerResponseHandle *, GBytes *, GError **): assertion 'response_handle->response_handle != nullptr' failed
```

**After**:

- Receiving a null message is handled as expected from the framework side documentation:

9287e81d52/packages/flutter/lib/src/services/platform_channel.dart (L149-L150)

## Related Issue

Fixes https://github.com/flutter/flutter/issues/128704

## Tests

Adds 2 tests.
This commit is contained in:
Bruno Leroux
2023-06-15 15:04:00 +02:00
committed by GitHub
parent 808065cb76
commit d4326f7b08
5 changed files with 53 additions and 3 deletions

View File

@@ -232,7 +232,6 @@ G_MODULE_EXPORT void fl_basic_message_channel_send(FlBasicMessageChannel* self,
GAsyncReadyCallback callback,
gpointer user_data) {
g_return_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self));
g_return_if_fail(message != nullptr);
g_autoptr(GTask) task =
callback != nullptr ? g_task_new(self, cancellable, callback, user_data)

View File

@@ -62,7 +62,8 @@ TEST(FlBasicMessageChannelTest, SendMessageWithoutResponse) {
}
// NOLINTEND(clang-analyzer-core.StackAddressEscape)
// Called when the message response is received in the SendMessage test.
// Called when the message response is received in the SendMessageWithResponse
// test.
static void echo_response_cb(GObject* object,
GAsyncResult* result,
gpointer user_data) {
@@ -189,3 +190,35 @@ TEST(FlBasicMessageChannelTest, ReceiveMessage) {
// Blocks here until response_cb is called.
g_main_loop_run(loop);
}
// Called when the message response is received in the
// SendNullMessageWithResponse test.
static void null_message_response_cb(GObject* object,
GAsyncResult* result,
gpointer user_data) {
g_autoptr(GError) error = nullptr;
g_autoptr(FlValue) message = fl_basic_message_channel_send_finish(
FL_BASIC_MESSAGE_CHANNEL(object), result, &error);
EXPECT_NE(message, nullptr);
EXPECT_EQ(error, nullptr);
EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_NULL);
g_main_loop_quit(static_cast<GMainLoop*>(user_data));
}
// Checks sending a null message with a response works.
TEST(FlBasicMessageChannelTest, SendNullMessageWithResponse) {
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
g_autoptr(FlEngine) engine = make_mock_engine();
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new();
g_autoptr(FlBasicMessageChannel) channel = fl_basic_message_channel_new(
messenger, "test/echo", FL_MESSAGE_CODEC(codec));
fl_basic_message_channel_send(channel, nullptr, nullptr,
null_message_response_cb, loop);
// Blocks here until null_message_response_cb is called.
g_main_loop_run(loop);
}

View File

@@ -420,6 +420,10 @@ static GBytes* fl_standard_message_codec_encode_message(FlMessageCodec* codec,
static FlValue* fl_standard_message_codec_decode_message(FlMessageCodec* codec,
GBytes* message,
GError** error) {
if (g_bytes_get_size(message) == 0) {
return fl_value_new_null();
}
FlStandardMessageCodec* self =
reinterpret_cast<FlStandardMessageCodec*>(codec);

View File

@@ -60,6 +60,19 @@ TEST(FlStandardMessageCodecTest, EncodeNull) {
EXPECT_STREQ(hex_string, "00");
}
TEST(FlStandardMessageCodecTest, DecodeNull) {
// Regression test for https://github.com/flutter/flutter/issues/128704.
g_autoptr(FlStandardMessageCodec) codec = fl_standard_message_codec_new();
g_autoptr(GBytes) data = g_bytes_new(nullptr, 0);
g_autoptr(GError) error = nullptr;
g_autoptr(FlValue) value =
fl_message_codec_decode_message(FL_MESSAGE_CODEC(codec), data, &error);
EXPECT_FALSE(value == nullptr);
EXPECT_EQ(fl_value_get_type(value), FL_VALUE_TYPE_NULL);
}
static gchar* encode_bool(gboolean value) {
g_autoptr(FlValue) v = fl_value_new_bool(value);
return encode_message(v);

View File

@@ -171,7 +171,8 @@ gboolean fl_basic_message_channel_respond(
/**
* fl_basic_message_channel_send:
* @channel: an #FlBasicMessageChannel.
* @message: message to send, must match what the #FlMessageCodec supports.
* @message: (allow-none): message to send, must match what the #FlMessageCodec
* supports.
* @cancellable: (allow-none): a #GCancellable or %NULL.
* @callback: (scope async): (allow-none): a #GAsyncReadyCallback to call when
* the request is satisfied or %NULL to ignore the response.