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

Commit beaac52

Browse files
authored
[Linux] Expose channel buffers 'resize' and 'overflow' control commands (#44636)
## 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 ## Related Issue Linux implementation for flutter/flutter#132386 ## Tests Adds two tests.
1 parent 5e84d73 commit beaac52

File tree

7 files changed

+296
-1
lines changed

7 files changed

+296
-1
lines changed

shell/platform/linux/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ source_set("flutter_linux_sources") {
158158
]
159159

160160
deps = [
161+
"//flutter/fml",
161162
"//flutter/shell/platform/common:common_cpp_enums",
162163
"//flutter/shell/platform/common:common_cpp_input",
163164
"//flutter/shell/platform/common:common_cpp_switches",

shell/platform/linux/fl_binary_messenger.cc

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,20 @@
55
#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h"
66
#include "flutter/shell/platform/linux/fl_binary_messenger_private.h"
77

8+
#include "flutter/fml/logging.h"
89
#include "flutter/shell/platform/linux/fl_engine_private.h"
10+
#include "flutter/shell/platform/linux/fl_method_codec_private.h"
911
#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
12+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
13+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h"
14+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h"
1015

1116
#include <gmodule.h>
1217

18+
static constexpr char kControlChannelName[] = "dev.flutter/channel-buffers";
19+
static constexpr char kResizeMethod[] = "resize";
20+
static constexpr char kOverflowMethod[] = "overflow";
21+
1322
G_DEFINE_QUARK(fl_binary_messenger_codec_error_quark,
1423
fl_binary_messenger_codec_error)
1524

@@ -311,6 +320,67 @@ static GBytes* send_on_channel_finish(FlBinaryMessenger* messenger,
311320
return fl_engine_send_platform_message_finish(engine, r, error);
312321
}
313322

323+
// Completes method call and returns TRUE if the call was successful.
324+
static gboolean finish_method(GObject* object,
325+
GAsyncResult* result,
326+
GError** error) {
327+
g_autoptr(FlMethodResponse) response = fl_method_channel_invoke_method_finish(
328+
FL_METHOD_CHANNEL(object), result, error);
329+
if (response == nullptr) {
330+
return FALSE;
331+
}
332+
return fl_method_response_get_result(response, error) != nullptr;
333+
}
334+
335+
// Called when a response is received for the resize channel message.
336+
static void resize_channel_response_cb(GObject* object,
337+
GAsyncResult* result,
338+
gpointer user_data) {
339+
g_autoptr(GError) error = nullptr;
340+
if (!finish_method(object, result, &error)) {
341+
g_warning("Failed to resize channel: %s", error->message);
342+
}
343+
}
344+
345+
static void resize_channel(FlBinaryMessenger* messenger,
346+
const gchar* channel,
347+
int64_t new_size) {
348+
FML_DCHECK(new_size >= 0);
349+
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
350+
g_autoptr(FlValue) args = fl_value_new_list();
351+
fl_value_append_take(args, fl_value_new_string(channel));
352+
fl_value_append_take(args, fl_value_new_int(new_size));
353+
g_autoptr(GBytes) message = fl_method_codec_encode_method_call(
354+
FL_METHOD_CODEC(codec), kResizeMethod, args, nullptr);
355+
fl_binary_messenger_send_on_channel(messenger, kControlChannelName, message,
356+
nullptr, resize_channel_response_cb,
357+
nullptr);
358+
}
359+
360+
// Called when a response is received for the allow channel overflow message.
361+
static void set_allow_channel_overflowl_response_cb(GObject* object,
362+
GAsyncResult* result,
363+
gpointer user_data) {
364+
g_autoptr(GError) error = nullptr;
365+
if (!finish_method(object, result, &error)) {
366+
g_warning("Failed to set allow channel overflow: %s", error->message);
367+
}
368+
}
369+
370+
static void set_allow_channel_overflow(FlBinaryMessenger* messenger,
371+
const gchar* channel,
372+
bool allowed) {
373+
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
374+
g_autoptr(FlValue) args = fl_value_new_list();
375+
fl_value_append_take(args, fl_value_new_string(channel));
376+
fl_value_append_take(args, fl_value_new_bool(allowed));
377+
g_autoptr(GBytes) message = fl_method_codec_encode_method_call(
378+
FL_METHOD_CODEC(codec), kOverflowMethod, args, nullptr);
379+
fl_binary_messenger_send_on_channel(
380+
messenger, kControlChannelName, message, nullptr,
381+
set_allow_channel_overflowl_response_cb, nullptr);
382+
}
383+
314384
static void fl_binary_messenger_impl_class_init(
315385
FlBinaryMessengerImplClass* klass) {
316386
G_OBJECT_CLASS(klass)->dispose = fl_binary_messenger_impl_dispose;
@@ -322,6 +392,8 @@ static void fl_binary_messenger_impl_iface_init(
322392
iface->send_response = send_response;
323393
iface->send_on_channel = send_on_channel;
324394
iface->send_on_channel_finish = send_on_channel_finish;
395+
iface->resize_channel = resize_channel;
396+
iface->set_allow_channel_overflow = set_allow_channel_overflow;
325397
}
326398

327399
static void fl_binary_messenger_impl_init(FlBinaryMessengerImpl* self) {
@@ -397,3 +469,22 @@ G_MODULE_EXPORT GBytes* fl_binary_messenger_send_on_channel_finish(
397469
return FL_BINARY_MESSENGER_GET_IFACE(self)->send_on_channel_finish(
398470
self, result, error);
399471
}
472+
473+
G_MODULE_EXPORT void fl_binary_messenger_resize_channel(FlBinaryMessenger* self,
474+
const gchar* channel,
475+
int64_t new_size) {
476+
g_return_if_fail(FL_IS_BINARY_MESSENGER(self));
477+
478+
return FL_BINARY_MESSENGER_GET_IFACE(self)->resize_channel(self, channel,
479+
new_size);
480+
}
481+
482+
G_MODULE_EXPORT void fl_binary_messenger_set_allow_channel_overflow(
483+
FlBinaryMessenger* self,
484+
const gchar* channel,
485+
bool allowed) {
486+
g_return_if_fail(FL_IS_BINARY_MESSENGER(self));
487+
488+
return FL_BINARY_MESSENGER_GET_IFACE(self)->set_allow_channel_overflow(
489+
self, channel, allowed);
490+
}

shell/platform/linux/fl_binary_messenger_test.cc

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@
88
#include <pthread.h>
99
#include <cstring>
1010

11+
#include "flutter/shell/platform/embedder/embedder.h"
12+
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
1113
#include "flutter/shell/platform/linux/fl_binary_messenger_private.h"
1214
#include "flutter/shell/platform/linux/fl_engine_private.h"
1315
#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h"
16+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
17+
#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h"
1418
#include "flutter/shell/platform/linux/testing/fl_test.h"
1519
#include "flutter/shell/platform/linux/testing/mock_binary_messenger_response_handle.h"
1620
#include "flutter/shell/platform/linux/testing/mock_renderer.h"
@@ -126,12 +130,26 @@ static GBytes* send_on_channel_finish(FlBinaryMessenger* messenger,
126130
return g_bytes_new(text, strlen(text));
127131
}
128132

133+
static void resize_channel(FlBinaryMessenger* messenger,
134+
const gchar* channel,
135+
int64_t new_size) {
136+
// Fake implementation. Do nothing.
137+
}
138+
139+
static void set_allow_channel_overflow(FlBinaryMessenger* messenger,
140+
const gchar* channel,
141+
bool allowed) {
142+
// Fake implementation. Do nothing.
143+
}
144+
129145
static void fl_fake_binary_messenger_iface_init(
130146
FlBinaryMessengerInterface* iface) {
131147
iface->set_message_handler_on_channel = set_message_handler_on_channel;
132148
iface->send_response = send_response;
133149
iface->send_on_channel = send_on_channel;
134150
iface->send_on_channel_finish = send_on_channel_finish;
151+
iface->resize_channel = resize_channel;
152+
iface->set_allow_channel_overflow = set_allow_channel_overflow;
135153
}
136154

137155
static void fl_fake_binary_messenger_init(FlFakeBinaryMessenger* self) {}
@@ -386,6 +404,105 @@ TEST(FlBinaryMessengerTest, ReceiveMessage) {
386404
g_main_loop_run(loop);
387405
}
388406

407+
// MOCK_ENGINE_PROC is leaky by design.
408+
// NOLINTBEGIN(clang-analyzer-core.StackAddressEscape)
409+
410+
// Checks if the 'resize' command is sent and is well-formed.
411+
TEST(FlBinaryMessengerTest, ResizeChannel) {
412+
g_autoptr(FlEngine) engine = make_mock_engine();
413+
FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine);
414+
415+
bool called = false;
416+
417+
FlutterEngineSendPlatformMessageFnPtr old_handler =
418+
embedder_api->SendPlatformMessage;
419+
embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC(
420+
SendPlatformMessage,
421+
([&called, old_handler](auto engine,
422+
const FlutterPlatformMessage* message) {
423+
// Expect to receive a message on the "control" channel.
424+
if (strcmp(message->channel, "dev.flutter/channel-buffers") != 0) {
425+
return old_handler(engine, message);
426+
}
427+
428+
called = true;
429+
430+
// The expected content was created from the following Dart code:
431+
// MethodCall call = MethodCall('resize', ['flutter/test',3]);
432+
// StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List();
433+
const int expected_message_size = 29;
434+
EXPECT_EQ(message->message_size,
435+
static_cast<size_t>(expected_message_size));
436+
int expected[expected_message_size] = {
437+
7, 6, 114, 101, 115, 105, 122, 101, 12, 2,
438+
7, 12, 102, 108, 117, 116, 116, 101, 114, 47,
439+
116, 101, 115, 116, 3, 3, 0, 0, 0};
440+
for (size_t i = 0; i < expected_message_size; i++) {
441+
EXPECT_EQ(message->message[i], expected[i]);
442+
}
443+
444+
return kSuccess;
445+
}));
446+
447+
g_autoptr(GError) error = nullptr;
448+
EXPECT_TRUE(fl_engine_start(engine, &error));
449+
EXPECT_EQ(error, nullptr);
450+
451+
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
452+
fl_binary_messenger_resize_channel(messenger, "flutter/test", 3);
453+
454+
EXPECT_TRUE(called);
455+
}
456+
457+
// Checks if the 'overflow' command is sent and is well-formed.
458+
TEST(FlBinaryMessengerTest, AllowOverflowChannel) {
459+
g_autoptr(FlEngine) engine = make_mock_engine();
460+
FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine);
461+
462+
bool called = false;
463+
464+
FlutterEngineSendPlatformMessageFnPtr old_handler =
465+
embedder_api->SendPlatformMessage;
466+
embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC(
467+
SendPlatformMessage,
468+
([&called, old_handler](auto engine,
469+
const FlutterPlatformMessage* message) {
470+
// Expect to receive a message on the "control" channel.
471+
if (strcmp(message->channel, "dev.flutter/channel-buffers") != 0) {
472+
return old_handler(engine, message);
473+
}
474+
475+
called = true;
476+
477+
// The expected content was created from the following Dart code:
478+
// MethodCall call = MethodCall('overflow',['flutter/test', true]);
479+
// StandardMethodCodec().encodeMethodCall(call).buffer.asUint8List();
480+
const int expected_message_size = 27;
481+
EXPECT_EQ(message->message_size,
482+
static_cast<size_t>(expected_message_size));
483+
int expected[expected_message_size] = {
484+
7, 8, 111, 118, 101, 114, 102, 108, 111, 119, 12, 2, 7, 12,
485+
102, 108, 117, 116, 116, 101, 114, 47, 116, 101, 115, 116, 1};
486+
for (size_t i = 0; i < expected_message_size; i++) {
487+
EXPECT_EQ(message->message[i], expected[i]);
488+
}
489+
490+
return kSuccess;
491+
}));
492+
493+
g_autoptr(GError) error = nullptr;
494+
EXPECT_TRUE(fl_engine_start(engine, &error));
495+
EXPECT_EQ(error, nullptr);
496+
497+
FlBinaryMessenger* messenger = fl_binary_messenger_new(engine);
498+
fl_binary_messenger_set_allow_channel_overflow(messenger, "flutter/test",
499+
true);
500+
501+
EXPECT_TRUE(called);
502+
}
503+
504+
// NOLINTEND(clang-analyzer-core.StackAddressEscape)
505+
389506
struct RespondsOnBackgroundThreadInfo {
390507
FlBinaryMessenger* messenger;
391508
FlBinaryMessengerResponseHandle* response_handle;

shell/platform/linux/fl_keyboard_manager_test.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,20 @@ static GBytes* fl_mock_key_binary_messenger_send_on_channel_finish(
215215
return static_cast<GBytes*>(g_task_propagate_pointer(G_TASK(result), error));
216216
}
217217

218+
static void fl_mock_binary_messenger_resize_channel(
219+
FlBinaryMessenger* messenger,
220+
const gchar* channel,
221+
int64_t new_size) {
222+
// Mock implementation. Do nothing.
223+
}
224+
225+
static void fl_mock_binary_messenger_set_allow_channel_overflow(
226+
FlBinaryMessenger* messenger,
227+
const gchar* channel,
228+
bool allowed) {
229+
// Mock implementation. Do nothing.
230+
}
231+
218232
static void fl_mock_key_binary_messenger_iface_init(
219233
FlBinaryMessengerInterface* iface) {
220234
iface->set_message_handler_on_channel =
@@ -236,6 +250,9 @@ static void fl_mock_key_binary_messenger_iface_init(
236250
iface->send_on_channel = fl_mock_key_binary_messenger_send_on_channel;
237251
iface->send_on_channel_finish =
238252
fl_mock_key_binary_messenger_send_on_channel_finish;
253+
iface->resize_channel = fl_mock_binary_messenger_resize_channel;
254+
iface->set_allow_channel_overflow =
255+
fl_mock_binary_messenger_set_allow_channel_overflow;
239256
}
240257

241258
static void fl_mock_key_binary_messenger_init(FlMockKeyBinaryMessenger* self) {}

shell/platform/linux/public/flutter_linux/fl_binary_messenger.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#error "Only <flutter_linux/flutter_linux.h> can be included directly."
1010
#endif
1111

12+
#include "fl_value.h"
13+
1214
#include <gio/gio.h>
1315
#include <glib-object.h>
1416
#include <gmodule.h>
@@ -91,6 +93,14 @@ struct _FlBinaryMessengerInterface {
9193
GBytes* (*send_on_channel_finish)(FlBinaryMessenger* messenger,
9294
GAsyncResult* result,
9395
GError** error);
96+
97+
void (*resize_channel)(FlBinaryMessenger* messenger,
98+
const gchar* channel,
99+
int64_t new_size);
100+
101+
void (*set_allow_channel_overflow)(FlBinaryMessenger* messenger,
102+
const gchar* channel,
103+
bool allowed);
94104
};
95105

96106
struct _FlBinaryMessengerResponseHandleClass {
@@ -174,7 +184,7 @@ void fl_binary_messenger_send_on_channel(FlBinaryMessenger* messenger,
174184

175185
/**
176186
* fl_binary_messenger_send_on_channel_finish:
177-
* @binary_messenger: an #FlBinaryMessenger.
187+
* @messenger: an #FlBinaryMessenger.
178188
* @result: a #GAsyncResult.
179189
* @error: (allow-none): #GError location to store the error occurring, or %NULL
180190
* to ignore.
@@ -187,6 +197,33 @@ GBytes* fl_binary_messenger_send_on_channel_finish(FlBinaryMessenger* messenger,
187197
GAsyncResult* result,
188198
GError** error);
189199

200+
/**
201+
* fl_binary_messenger_resize_channel:
202+
* @binary_messenger: an #FlBinaryMessenger.
203+
* @channel: channel to be resize.
204+
* @new_size: the new size for the channel buffer.
205+
*
206+
* Sends a message to the control channel asking to resize a channel buffer.
207+
*/
208+
void fl_binary_messenger_resize_channel(FlBinaryMessenger* messenger,
209+
const gchar* channel,
210+
int64_t new_size);
211+
212+
/**
213+
* fl_binary_messenger_set_allow_channel_overflow:
214+
* @messenger: an #FlBinaryMessenger.
215+
* @channel: channel to be allowed to overflow silently.
216+
* @allowed: when true the channel is expected to overflow and warning messages
217+
* will not be shown.
218+
*
219+
* Sends a message to the control channel asking to allow or disallow a channel
220+
* to overflow silently.
221+
*/
222+
void fl_binary_messenger_set_allow_channel_overflow(
223+
FlBinaryMessenger* messenger,
224+
const gchar* channel,
225+
bool allowed);
226+
190227
G_END_DECLS
191228

192229
#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_BINARY_MESSENGER_H_

0 commit comments

Comments
 (0)