From 15fad12becd3017e0e5b786ff6fd55f694b540f3 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Fri, 13 Dec 2024 16:29:40 +1300 Subject: [PATCH 1/2] Migrate FlBinaryMessenger using embedder API instead of mock engine. This allows us to remove most of the remaining mock engine code. --- shell/platform/linux/fl_binary_messenger.cc | 40 +- .../linux/fl_binary_messenger_private.h | 19 + .../linux/fl_binary_messenger_test.cc | 756 ++++++++---------- shell/platform/linux/testing/mock_engine.cc | 166 ---- 4 files changed, 362 insertions(+), 619 deletions(-) diff --git a/shell/platform/linux/fl_binary_messenger.cc b/shell/platform/linux/fl_binary_messenger.cc index 4453456ec1113..c0d6773e7b284 100644 --- a/shell/platform/linux/fl_binary_messenger.cc +++ b/shell/platform/linux/fl_binary_messenger.cc @@ -155,21 +155,9 @@ static gboolean fl_binary_messenger_platform_message_cb( GBytes* message, const FlutterPlatformMessageResponseHandle* response_handle, void* user_data) { - FlBinaryMessengerImpl* self = FL_BINARY_MESSENGER_IMPL(user_data); - - PlatformMessageHandler* handler = static_cast( - g_hash_table_lookup(self->platform_message_handlers, channel)); - if (handler == nullptr) { - return FALSE; - } - - g_autoptr(FlBinaryMessengerResponseHandleImpl) handle = - fl_binary_messenger_response_handle_impl_new(self, response_handle); - handler->message_handler(FL_BINARY_MESSENGER(self), channel, message, - FL_BINARY_MESSENGER_RESPONSE_HANDLE(handle), - handler->message_handler_data); - - return TRUE; + FlBinaryMessenger* self = FL_BINARY_MESSENGER(user_data); + return fl_binary_messenger_handle_message(self, channel, message, + response_handle); } static void fl_binary_messenger_impl_dispose(GObject* object) { @@ -487,6 +475,28 @@ G_MODULE_EXPORT void fl_binary_messenger_set_warns_on_channel_overflow( self, channel, warns); } +gboolean fl_binary_messenger_handle_message( + FlBinaryMessenger* messenger, + const gchar* channel, + GBytes* message, + const FlutterPlatformMessageResponseHandle* response_handle) { + FlBinaryMessengerImpl* self = FL_BINARY_MESSENGER_IMPL(messenger); + + PlatformMessageHandler* handler = static_cast( + g_hash_table_lookup(self->platform_message_handlers, channel)); + if (handler == nullptr) { + return FALSE; + } + + g_autoptr(FlBinaryMessengerResponseHandleImpl) handle = + fl_binary_messenger_response_handle_impl_new(self, response_handle); + handler->message_handler(FL_BINARY_MESSENGER(self), channel, message, + FL_BINARY_MESSENGER_RESPONSE_HANDLE(handle), + handler->message_handler_data); + + return TRUE; +} + void fl_binary_messenger_shutdown(FlBinaryMessenger* self) { g_return_if_fail(FL_IS_BINARY_MESSENGER(self)); diff --git a/shell/platform/linux/fl_binary_messenger_private.h b/shell/platform/linux/fl_binary_messenger_private.h index e444e8f94e31b..0925759972eaa 100644 --- a/shell/platform/linux/fl_binary_messenger_private.h +++ b/shell/platform/linux/fl_binary_messenger_private.h @@ -7,6 +7,7 @@ #include +#include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" G_BEGIN_DECLS @@ -22,6 +23,24 @@ G_BEGIN_DECLS */ FlBinaryMessenger* fl_binary_messenger_new(FlEngine* engine); +/** + * fl_binary_messenger_handle_message: + * @messenger: an #FlBinaryMessenger. + * @channel: channel message received on. + * @message: message data. + * @response_handle: handle to provide to + * fl_engine_send_platform_message_response(). + * + * Handles a message received from the engine. Available for testing purposes. + * + * Returns: %TRUE if the message is handled. + */ +gboolean fl_binary_messenger_handle_message( + FlBinaryMessenger* messenger, + const gchar* channel, + GBytes* message, + const FlutterPlatformMessageResponseHandle* response_handle); + /** * fl_binary_messenger_shutdown: * @messenger: an #FlBinaryMessenger. diff --git a/shell/platform/linux/fl_binary_messenger_test.cc b/shell/platform/linux/fl_binary_messenger_test.cc index 8f03eb514057c..49d75a0f0fbef 100644 --- a/shell/platform/linux/fl_binary_messenger_test.cc +++ b/shell/platform/linux/fl_binary_messenger_test.cc @@ -13,419 +13,367 @@ #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" -#include "flutter/shell/platform/linux/testing/fl_test.h" -#include "flutter/shell/platform/linux/testing/mock_renderer.h" -G_DECLARE_FINAL_TYPE(FlFakeBinaryMessengerResponseHandle, - fl_fake_binary_messenger_response_handle, - FL, - FAKE_BINARY_MESSENGER_RESPONSE_HANDLE, - FlBinaryMessengerResponseHandle) - -struct _FlFakeBinaryMessengerResponseHandle { - FlBinaryMessengerResponseHandle parent_instance; -}; - -G_DEFINE_TYPE(FlFakeBinaryMessengerResponseHandle, - fl_fake_binary_messenger_response_handle, - fl_binary_messenger_response_handle_get_type()); - -static void fl_fake_binary_messenger_response_handle_class_init( - FlFakeBinaryMessengerResponseHandleClass* klass) {} - -static void fl_fake_binary_messenger_response_handle_init( - FlFakeBinaryMessengerResponseHandle* self) {} - -FlFakeBinaryMessengerResponseHandle* -fl_fake_binary_messenger_response_handle_new() { - return FL_FAKE_BINARY_MESSENGER_RESPONSE_HANDLE( - g_object_new(fl_fake_binary_messenger_response_handle_get_type(), NULL)); -} - -G_DECLARE_FINAL_TYPE(FlFakeBinaryMessenger, - fl_fake_binary_messenger, - FL, - FAKE_BINARY_MESSENGER, - GObject) - -struct _FlFakeBinaryMessenger { - GObject parent_instance; - - GMainLoop* loop; - GAsyncReadyCallback send_callback; - gpointer send_callback_user_data; - FlBinaryMessengerMessageHandler message_handler; - gpointer message_handler_user_data; -}; +// Checks can send a message. +TEST(FlBinaryMessengerTest, Send) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); -static void fl_fake_binary_messenger_iface_init( - FlBinaryMessengerInterface* iface); + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); -G_DEFINE_TYPE_WITH_CODE( - FlFakeBinaryMessenger, - fl_fake_binary_messenger, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(fl_binary_messenger_get_type(), - fl_fake_binary_messenger_iface_init)) + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &error)); + EXPECT_EQ(error, nullptr); -static void fl_fake_binary_messenger_class_init( - FlFakeBinaryMessengerClass* klass) {} + FlutterDataCallback response_callback; + void* response_callback_user_data; + embedder_api->PlatformMessageCreateResponseHandle = MOCK_ENGINE_PROC( + PlatformMessageCreateResponseHandle, + ([&response_callback, &response_callback_user_data]( + auto engine, FlutterDataCallback data_callback, void* user_data, + FlutterPlatformMessageResponseHandle** response_out) { + response_callback = data_callback; + response_callback_user_data = user_data; + return kSuccess; + })); + embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC( + SendPlatformMessage, + ([&response_callback, &response_callback_user_data]( + auto engine, const FlutterPlatformMessage* message) { + EXPECT_STREQ(message->channel, "test"); + g_autofree gchar* text = + g_strndup(reinterpret_cast(message->message), + message->message_size); + EXPECT_STREQ(text, "Marco!"); + + const gchar* response = "Polo!"; + response_callback(reinterpret_cast(response), + strlen(response), response_callback_user_data); -static gboolean send_message_cb(gpointer user_data) { - FlFakeBinaryMessenger* self = FL_FAKE_BINARY_MESSENGER(user_data); + return kSuccess; + })); + g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); const char* text = "Marco!"; g_autoptr(GBytes) message = g_bytes_new(text, strlen(text)); - self->message_handler(FL_BINARY_MESSENGER(self), "CHANNEL", message, - FL_BINARY_MESSENGER_RESPONSE_HANDLE( - fl_fake_binary_messenger_response_handle_new()), - self->message_handler_user_data); - - return FALSE; -} - -static void set_message_handler_on_channel( - FlBinaryMessenger* messenger, - const gchar* channel, - FlBinaryMessengerMessageHandler handler, - gpointer user_data, - GDestroyNotify destroy_notify) { - FlFakeBinaryMessenger* self = FL_FAKE_BINARY_MESSENGER(messenger); + fl_binary_messenger_send_on_channel( + messenger, "test", message, nullptr, + [](GObject* object, GAsyncResult* result, gpointer user_data) { + g_autoptr(GError) error = nullptr; + g_autoptr(GBytes) message = fl_binary_messenger_send_on_channel_finish( + FL_BINARY_MESSENGER(object), result, &error); + EXPECT_NE(message, nullptr); + EXPECT_EQ(error, nullptr); + + g_autofree gchar* text = g_strndup( + static_cast(g_bytes_get_data(message, nullptr)), + g_bytes_get_size(message)); + EXPECT_STREQ(text, "Polo!"); + + g_main_loop_quit(static_cast(user_data)); + }, + loop); - EXPECT_STREQ(channel, "CHANNEL"); - - // Send message. - self->message_handler = handler; - self->message_handler_user_data = user_data; - g_idle_add(send_message_cb, messenger); + g_main_loop_run(loop); } -static gboolean send_response(FlBinaryMessenger* messenger, - FlBinaryMessengerResponseHandle* response_handle, - GBytes* response, - GError** error) { - FlFakeBinaryMessenger* self = FL_FAKE_BINARY_MESSENGER(messenger); - - EXPECT_TRUE(FL_IS_FAKE_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle)); - - g_autofree gchar* text = - g_strndup(static_cast(g_bytes_get_data(response, nullptr)), - g_bytes_get_size(response)); - EXPECT_STREQ(text, "Polo!"); +// Checks sending nullptr for a message works. +TEST(FlBinaryMessengerTest, SendNullptr) { + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); - g_main_loop_quit(self->loop); + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &error)); + EXPECT_EQ(error, nullptr); - return TRUE; -} + bool called = false; + embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC( + SendPlatformMessage, + ([&called](auto engine, const FlutterPlatformMessage* message) { + called = true; -static gboolean send_ready_cb(gpointer user_data) { - FlFakeBinaryMessenger* self = FL_FAKE_BINARY_MESSENGER(user_data); + EXPECT_STREQ(message->channel, "test"); + EXPECT_EQ(message->message_size, static_cast(0)); - self->send_callback(G_OBJECT(self), NULL, self->send_callback_user_data); + return kSuccess; + })); - return FALSE; + g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + fl_binary_messenger_send_on_channel(messenger, "test", nullptr, nullptr, + nullptr, nullptr); + EXPECT_TRUE(called); } -static void send_on_channel(FlBinaryMessenger* messenger, - const gchar* channel, - GBytes* message, - GCancellable* cancellable, - GAsyncReadyCallback callback, - gpointer user_data) { - FlFakeBinaryMessenger* self = FL_FAKE_BINARY_MESSENGER(messenger); - - EXPECT_STREQ(channel, "CHANNEL"); - g_autofree gchar* text = - g_strndup(static_cast(g_bytes_get_data(message, nullptr)), - g_bytes_get_size(message)); - EXPECT_STREQ(text, "Marco!"); - - // Send response. - self->send_callback = callback; - self->send_callback_user_data = user_data; - g_idle_add(send_ready_cb, messenger); -} +// Checks sending a zero length message works. +TEST(FlBinaryMessengerTest, SendEmpty) { + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); -static GBytes* send_on_channel_finish(FlBinaryMessenger* messenger, - GAsyncResult* result, - GError** error) { - const char* text = "Polo!"; - return g_bytes_new(text, strlen(text)); -} + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &error)); + EXPECT_EQ(error, nullptr); -static void resize_channel(FlBinaryMessenger* messenger, - const gchar* channel, - int64_t new_size) { - // Fake implementation. Do nothing. -} + bool called = false; + embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC( + SendPlatformMessage, + ([&called](auto engine, const FlutterPlatformMessage* message) { + called = true; -static void set_warns_on_channel_overflow(FlBinaryMessenger* messenger, - const gchar* channel, - bool warns) { - // Fake implementation. Do nothing. -} + EXPECT_STREQ(message->channel, "test"); + EXPECT_EQ(message->message_size, static_cast(0)); -static void fl_fake_binary_messenger_iface_init( - FlBinaryMessengerInterface* iface) { - iface->set_message_handler_on_channel = set_message_handler_on_channel; - iface->send_response = send_response; - iface->send_on_channel = send_on_channel; - iface->send_on_channel_finish = send_on_channel_finish; - iface->resize_channel = resize_channel; - iface->set_warns_on_channel_overflow = set_warns_on_channel_overflow; + return kSuccess; + })); + g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_autoptr(GBytes) message = g_bytes_new(nullptr, 0); + fl_binary_messenger_send_on_channel(messenger, "test", message, nullptr, + nullptr, nullptr); + EXPECT_TRUE(called); } -static void fl_fake_binary_messenger_init(FlFakeBinaryMessenger* self) {} +// Checks the engine returning a nullptr message work. +TEST(FlBinaryMessengerTest, NullptrResponse) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); -static FlBinaryMessenger* fl_fake_binary_messenger_new(GMainLoop* loop) { - FlFakeBinaryMessenger* self = FL_FAKE_BINARY_MESSENGER( - g_object_new(fl_fake_binary_messenger_get_type(), NULL)); - self->loop = loop; - return FL_BINARY_MESSENGER(self); -} + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); -// Called when the message response is received in the FakeMessengerSend test. -static void fake_response_cb(GObject* object, - GAsyncResult* result, - gpointer user_data) { g_autoptr(GError) error = nullptr; - g_autoptr(GBytes) message = fl_binary_messenger_send_on_channel_finish( - FL_BINARY_MESSENGER(object), result, &error); - EXPECT_NE(message, nullptr); + EXPECT_TRUE(fl_engine_start(engine, &error)); EXPECT_EQ(error, nullptr); - g_autofree gchar* text = - g_strndup(static_cast(g_bytes_get_data(message, nullptr)), - g_bytes_get_size(message)); - EXPECT_STREQ(text, "Polo!"); - - g_main_loop_quit(static_cast(user_data)); -} + FlutterDataCallback response_callback; + void* response_callback_user_data; + embedder_api->PlatformMessageCreateResponseHandle = MOCK_ENGINE_PROC( + PlatformMessageCreateResponseHandle, + ([&response_callback, &response_callback_user_data]( + auto engine, FlutterDataCallback data_callback, void* user_data, + FlutterPlatformMessageResponseHandle** response_out) { + response_callback = data_callback; + response_callback_user_data = user_data; + return kSuccess; + })); + embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC( + SendPlatformMessage, + ([&response_callback, &response_callback_user_data]( + auto engine, const FlutterPlatformMessage* message) { + EXPECT_STREQ(message->channel, "test"); + g_autofree gchar* text = + g_strndup(reinterpret_cast(message->message), + message->message_size); + EXPECT_STREQ(text, "Hello World!"); -// Checks can make a fake messenger and send a message. -TEST(FlBinaryMessengerTest, FakeMessengerSend) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + response_callback(nullptr, 0, response_callback_user_data); - g_autoptr(FlBinaryMessenger) messenger = fl_fake_binary_messenger_new(loop); - EXPECT_TRUE(FL_IS_FAKE_BINARY_MESSENGER(messenger)); + return kSuccess; + })); - const char* text = "Marco!"; + g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + const char* text = "Hello World!"; g_autoptr(GBytes) message = g_bytes_new(text, strlen(text)); - fl_binary_messenger_send_on_channel(messenger, "CHANNEL", message, nullptr, - fake_response_cb, loop); - - // Blocks here until fake_response_cb is called. - g_main_loop_run(loop); -} - -// Called when a message is received in the FakeMessengerReceive test. -static void fake_message_cb(FlBinaryMessenger* messenger, - const gchar* channel, - GBytes* message, - FlBinaryMessengerResponseHandle* response_handle, - gpointer user_data) { - EXPECT_STREQ(channel, "CHANNEL"); - - EXPECT_NE(message, nullptr); - g_autofree gchar* text = - g_strndup(static_cast(g_bytes_get_data(message, nullptr)), - g_bytes_get_size(message)); - EXPECT_STREQ(text, "Marco!"); - - const char* response_text = "Polo!"; - g_autoptr(GBytes) response = - g_bytes_new(response_text, strlen(response_text)); - g_autoptr(GError) error = nullptr; - EXPECT_TRUE(fl_binary_messenger_send_response(messenger, response_handle, - response, &error)); - EXPECT_EQ(error, nullptr); -} + fl_binary_messenger_send_on_channel( + messenger, "test", message, nullptr, + [](GObject* object, GAsyncResult* result, gpointer user_data) { + g_autoptr(GError) error = nullptr; + g_autoptr(GBytes) message = fl_binary_messenger_send_on_channel_finish( + FL_BINARY_MESSENGER(object), result, &error); + EXPECT_NE(message, nullptr); + EXPECT_EQ(error, nullptr); -// Checks can make a fake messenger and receive a message. -TEST(FlBinaryMessengerTest, FakeMessengerReceive) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlBinaryMessenger) messenger = fl_fake_binary_messenger_new(loop); - EXPECT_TRUE(FL_IS_FAKE_BINARY_MESSENGER(messenger)); + EXPECT_EQ(g_bytes_get_size(message), static_cast(0)); - fl_binary_messenger_set_message_handler_on_channel( - messenger, "CHANNEL", fake_message_cb, nullptr, nullptr); + g_main_loop_quit(static_cast(user_data)); + }, + loop); - // Blocks here until response is received in fake messenger. g_main_loop_run(loop); } -// Checks sending nullptr for a message works. -TEST(FlBinaryMessengerTest, SendNullptrMessage) { - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); - fl_binary_messenger_send_on_channel(messenger, "test/echo", nullptr, nullptr, - nullptr, nullptr); -} +// Checks the engine reporting a send failure is handled. +TEST(FlBinaryMessengerTest, SendFailure) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); -// Checks sending a zero length message works. -TEST(FlBinaryMessengerTest, SendEmptyMessage) { - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); - g_autoptr(GBytes) message = g_bytes_new(nullptr, 0); - fl_binary_messenger_send_on_channel(messenger, "test/echo", message, nullptr, - nullptr, nullptr); -} + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); -// Called when the message response is received in the SendMessage test. -static void echo_response_cb(GObject* object, - GAsyncResult* result, - gpointer user_data) { g_autoptr(GError) error = nullptr; - g_autoptr(GBytes) message = fl_binary_messenger_send_on_channel_finish( - FL_BINARY_MESSENGER(object), result, &error); - EXPECT_NE(message, nullptr); + EXPECT_TRUE(fl_engine_start(engine, &error)); EXPECT_EQ(error, nullptr); - g_autofree gchar* text = - g_strndup(static_cast(g_bytes_get_data(message, nullptr)), - g_bytes_get_size(message)); - EXPECT_STREQ(text, "Hello World!"); - - g_main_loop_quit(static_cast(user_data)); -} - -// Checks sending a message works. -TEST(FlBinaryMessengerTest, SendMessage) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + embedder_api->SendPlatformMessage = + MOCK_ENGINE_PROC(SendPlatformMessage, + ([](auto engine, const FlutterPlatformMessage* message) { + EXPECT_STREQ(message->channel, "test"); + return kInternalInconsistency; + })); - g_autoptr(FlEngine) engine = make_mock_engine(); g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); - const char* text = "Hello World!"; - g_autoptr(GBytes) message = g_bytes_new(text, strlen(text)); - fl_binary_messenger_send_on_channel(messenger, "test/echo", message, nullptr, - echo_response_cb, loop); + fl_binary_messenger_send_on_channel( + messenger, "test", nullptr, nullptr, + [](GObject* object, GAsyncResult* result, gpointer user_data) { + g_autoptr(GError) error = nullptr; + g_autoptr(GBytes) message = fl_binary_messenger_send_on_channel_finish( + FL_BINARY_MESSENGER(object), result, &error); + EXPECT_EQ(message, nullptr); + EXPECT_NE(error, nullptr); + EXPECT_STREQ(error->message, "Failed to send platform messages"); + + g_main_loop_quit(static_cast(user_data)); + }, + loop); - // Blocks here until echo_response_cb is called. g_main_loop_run(loop); } -// Called when the message response is received in the NullptrResponse test. -static void nullptr_response_cb(GObject* object, - GAsyncResult* result, - gpointer user_data) { +// Checks can receive a message. +TEST(FlBinaryMessengerTest, Receive) { + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + g_autoptr(GError) error = nullptr; - g_autoptr(GBytes) message = fl_binary_messenger_send_on_channel_finish( - FL_BINARY_MESSENGER(object), result, &error); - EXPECT_NE(message, nullptr); + EXPECT_TRUE(fl_engine_start(engine, &error)); EXPECT_EQ(error, nullptr); - EXPECT_EQ(g_bytes_get_size(message), static_cast(0)); + bool called = false; + embedder_api->SendPlatformMessageResponse = MOCK_ENGINE_PROC( + SendPlatformMessageResponse, + ([&called](auto engine, + const FlutterPlatformMessageResponseHandle* handle, + const uint8_t* data, size_t data_length) { + called = true; - g_main_loop_quit(static_cast(user_data)); -} + int fake_handle = *reinterpret_cast(handle); + EXPECT_EQ(fake_handle, 42); -// Checks the engine returning a nullptr message work. -TEST(FlBinaryMessengerTest, NullptrResponse) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + g_autofree gchar* text = + g_strndup(reinterpret_cast(data), data_length); + EXPECT_STREQ(text, "Polo!"); - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); - const char* text = "Hello World!"; - g_autoptr(GBytes) message = g_bytes_new(text, strlen(text)); - fl_binary_messenger_send_on_channel(messenger, "test/nullptr-response", - message, nullptr, nullptr_response_cb, - loop); + return kSuccess; + })); - // Blocks here until nullptr_response_cb is called. - g_main_loop_run(loop); -} + FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(engine); -// Called when the message response is received in the SendFailure test. -static void failure_response_cb(GObject* object, - GAsyncResult* result, - gpointer user_data) { - g_autoptr(GError) error = nullptr; - g_autoptr(GBytes) message = fl_binary_messenger_send_on_channel_finish( - FL_BINARY_MESSENGER(object), result, &error); - EXPECT_EQ(message, nullptr); - EXPECT_NE(error, nullptr); + // Listen for message. + fl_binary_messenger_set_message_handler_on_channel( + messenger, "test", + [](FlBinaryMessenger* messenger, const gchar* channel, GBytes* message, + FlBinaryMessengerResponseHandle* response_handle, gpointer user_data) { + g_autofree gchar* text = g_strndup( + static_cast(g_bytes_get_data(message, nullptr)), + g_bytes_get_size(message)); + EXPECT_STREQ(text, "Marco!"); + + const char* response_text = "Polo!"; + g_autoptr(GBytes) response = + g_bytes_new(response_text, strlen(response_text)); + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_binary_messenger_send_response( + messenger, response_handle, response, &error)); + EXPECT_EQ(error, nullptr); + }, + nullptr, nullptr); + + // Send message from engine. + const char* message_text = "Marco!"; + g_autoptr(GBytes) message = g_bytes_new(message_text, strlen(message_text)); + int fake_handle = 42; + fl_binary_messenger_handle_message( + messenger, "test", message, + reinterpret_cast( + &fake_handle)); - g_main_loop_quit(static_cast(user_data)); + EXPECT_TRUE(called); } -// Checks the engine reporting a send failure is handled. -TEST(FlBinaryMessengerTest, SendFailure) { +// Checks receieved messages can be responded to on a thread. +TEST(FlBinaryMessengerTest, ReceiveRespondThread) { g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); - fl_binary_messenger_send_on_channel(messenger, "test/failure", nullptr, - nullptr, failure_response_cb, loop); - - // Blocks here until failure_response_cb is called. - g_main_loop_run(loop); -} + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); -// Called when a message is received from the engine in the ReceiveMessage test. -static void message_cb(FlBinaryMessenger* messenger, - const gchar* channel, - GBytes* message, - FlBinaryMessengerResponseHandle* response_handle, - gpointer user_data) { - EXPECT_NE(message, nullptr); - g_autofree gchar* text = - g_strndup(static_cast(g_bytes_get_data(message, nullptr)), - g_bytes_get_size(message)); - EXPECT_STREQ(text, "Marco!"); - - const char* response_text = "Polo!"; - g_autoptr(GBytes) response = - g_bytes_new(response_text, strlen(response_text)); g_autoptr(GError) error = nullptr; - EXPECT_TRUE(fl_binary_messenger_send_response(messenger, response_handle, - response, &error)); + EXPECT_TRUE(fl_engine_start(engine, &error)); EXPECT_EQ(error, nullptr); -} -// Called when a the test engine notifies us what response we sent in the -// ReceiveMessage test. -static void response_cb(FlBinaryMessenger* messenger, - const gchar* channel, - GBytes* message, - FlBinaryMessengerResponseHandle* response_handle, - gpointer user_data) { - EXPECT_NE(message, nullptr); - g_autofree gchar* text = - g_strndup(static_cast(g_bytes_get_data(message, nullptr)), - g_bytes_get_size(message)); - EXPECT_STREQ(text, "Polo!"); - - fl_binary_messenger_send_response(messenger, response_handle, nullptr, - nullptr); - - g_main_loop_quit(static_cast(user_data)); -} + embedder_api->SendPlatformMessageResponse = MOCK_ENGINE_PROC( + SendPlatformMessageResponse, + ([&loop](auto engine, const FlutterPlatformMessageResponseHandle* handle, + const uint8_t* data, size_t data_length) { + int fake_handle = *reinterpret_cast(handle); + EXPECT_EQ(fake_handle, 42); -// Checks the shell able to receive and respond to messages from the engine. -TEST(FlBinaryMessengerTest, ReceiveMessage) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + g_autofree gchar* text = + g_strndup(reinterpret_cast(data), data_length); + EXPECT_STREQ(text, "Polo!"); - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + g_main_loop_quit(loop); - // Listen for messages from the engine. - fl_binary_messenger_set_message_handler_on_channel( - messenger, "test/messages", message_cb, nullptr, nullptr); + return kSuccess; + })); - // Listen for response from the engine. - fl_binary_messenger_set_message_handler_on_channel( - messenger, "test/responses", response_cb, loop, nullptr); + FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(engine); - // Trigger the engine to send a message. - const char* text = "Marco!"; - g_autoptr(GBytes) message = g_bytes_new(text, strlen(text)); - fl_binary_messenger_send_on_channel(messenger, "test/send-message", message, - nullptr, nullptr, nullptr); + // Listen for message. + fl_binary_messenger_set_message_handler_on_channel( + messenger, "test", + [](FlBinaryMessenger* messenger, const gchar* channel, GBytes* message, + FlBinaryMessengerResponseHandle* response_handle, gpointer user_data) { + g_autofree gchar* text = g_strndup( + static_cast(g_bytes_get_data(message, nullptr)), + g_bytes_get_size(message)); + EXPECT_STREQ(text, "Marco!"); + + // Respond on a thread. + typedef struct { + FlBinaryMessenger* messenger; + FlBinaryMessengerResponseHandle* response_handle; + } ThreadData; + ThreadData* data = g_new0(ThreadData, 1); + data->messenger = + static_cast(g_object_ref(messenger)); + data->response_handle = static_cast( + g_object_ref(response_handle)); + g_autoptr(GThread) thread = g_thread_new( + nullptr, + [](gpointer user_data) { + g_autofree ThreadData* data = static_cast(user_data); + g_autoptr(FlBinaryMessenger) messenger = data->messenger; + g_autoptr(FlBinaryMessengerResponseHandle) response_handle = + data->response_handle; + + const char* response_text = "Polo!"; + g_autoptr(GBytes) response = + g_bytes_new(response_text, strlen(response_text)); + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_binary_messenger_send_response( + data->messenger, data->response_handle, response, &error)); + EXPECT_EQ(error, nullptr); + + return static_cast(nullptr); + }, + data); + }, + nullptr, nullptr); + + // Send message from engine. + const char* message_text = "Marco!"; + g_autoptr(GBytes) message = g_bytes_new(message_text, strlen(message_text)); + int fake_handle = 42; + fl_binary_messenger_handle_message( + messenger, "test", message, + reinterpret_cast( + &fake_handle)); - // Blocks here until response_cb is called. g_main_loop_run(loop); } @@ -434,7 +382,8 @@ TEST(FlBinaryMessengerTest, ReceiveMessage) { // Checks if the 'resize' command is sent and is well-formed. TEST(FlBinaryMessengerTest, ResizeChannel) { - g_autoptr(FlEngine) engine = make_mock_engine(); + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); bool called = false; @@ -481,7 +430,8 @@ TEST(FlBinaryMessengerTest, ResizeChannel) { // Checks if the 'overflow' command is sent and is well-formed. TEST(FlBinaryMessengerTest, WarnsOnOverflowChannel) { - g_autoptr(FlEngine) engine = make_mock_engine(); + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); bool called = false; @@ -526,26 +476,21 @@ TEST(FlBinaryMessengerTest, WarnsOnOverflowChannel) { EXPECT_TRUE(called); } -static gboolean quit_main_loop_cb(gpointer user_data) { - g_main_loop_quit(static_cast(user_data)); - return FALSE; -} - // Checks if error returned when invoking a command on the control channel // are handled. TEST(FlBinaryMessengerTest, ControlChannelErrorResponse) { g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); g_autoptr(GError) error = nullptr; EXPECT_TRUE(fl_engine_start(engine, &error)); EXPECT_EQ(error, nullptr); - FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); - + g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); bool called = false; - FlutterEngineSendPlatformMessageFnPtr old_handler = embedder_api->SendPlatformMessage; embedder_api->SendPlatformMessage = MOCK_ENGINE_PROC( @@ -561,7 +506,12 @@ TEST(FlBinaryMessengerTest, ControlChannelErrorResponse) { // Register a callback to quit the main loop when binary messenger work // ends. - g_idle_add(quit_main_loop_cb, loop); + g_idle_add( + [](gpointer user_data) { + g_main_loop_quit(static_cast(user_data)); + return FALSE; + }, + loop); // Simulates an internal error. return kInvalidArguments; @@ -572,102 +522,32 @@ TEST(FlBinaryMessengerTest, ControlChannelErrorResponse) { EXPECT_TRUE(called); - // Blocks here until quit_main_loop_cb is called. g_main_loop_run(loop); } // NOLINTEND(clang-analyzer-core.StackAddressEscape) -struct RespondsOnBackgroundThreadInfo { - FlBinaryMessenger* messenger; - FlBinaryMessengerResponseHandle* response_handle; - GMainLoop* loop; -}; - -static gboolean cleanup_responds_on_background_thread_info(gpointer user_data) { - RespondsOnBackgroundThreadInfo* info = - static_cast(user_data); - GMainLoop* loop = info->loop; - - g_object_unref(info->messenger); - g_object_unref(info->response_handle); - free(info); - - g_main_loop_quit(static_cast(loop)); - - return G_SOURCE_REMOVE; -} - -static void* response_from_thread_main(void* user_data) { - RespondsOnBackgroundThreadInfo* info = - static_cast(user_data); - - fl_binary_messenger_send_response(info->messenger, info->response_handle, - nullptr, nullptr); - - g_idle_add(cleanup_responds_on_background_thread_info, info); - - return nullptr; -} - -static void response_from_thread_cb( - FlBinaryMessenger* messenger, - const gchar* channel, - GBytes* message, - FlBinaryMessengerResponseHandle* response_handle, - gpointer user_data) { - EXPECT_NE(message, nullptr); - pthread_t thread; - RespondsOnBackgroundThreadInfo* info = - static_cast( - malloc(sizeof(RespondsOnBackgroundThreadInfo))); - info->messenger = FL_BINARY_MESSENGER(g_object_ref(messenger)); - info->response_handle = - FL_BINARY_MESSENGER_RESPONSE_HANDLE(g_object_ref(response_handle)); - info->loop = static_cast(user_data); - EXPECT_EQ(0, - pthread_create(&thread, nullptr, &response_from_thread_main, info)); -} - -TEST(FlBinaryMessengerTest, RespondOnBackgroundThread) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlEngine) engine = make_mock_engine(); - g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); - - // Listen for messages from the engine. - fl_binary_messenger_set_message_handler_on_channel( - messenger, "test/messages", message_cb, nullptr, nullptr); - - // Listen for response from the engine. - fl_binary_messenger_set_message_handler_on_channel( - messenger, "test/responses", response_from_thread_cb, loop, nullptr); - - // Trigger the engine to send a message. - const char* text = "Marco!"; - g_autoptr(GBytes) message = g_bytes_new(text, strlen(text)); - fl_binary_messenger_send_on_channel(messenger, "test/send-message", message, - nullptr, nullptr, nullptr); - - // Blocks here until response_cb is called. - g_main_loop_run(loop); -} +TEST(FlBinaryMessengerTest, DeletingEngineClearsHandlers) { + g_autoptr(FlDartProject) project = fl_dart_project_new(); + g_autoptr(FlEngine) engine = fl_engine_new(project); -static void kill_handler_notify_cb(gpointer was_called) { - *static_cast(was_called) = TRUE; -} + g_autoptr(GError) error = nullptr; + EXPECT_TRUE(fl_engine_start(engine, &error)); + EXPECT_EQ(error, nullptr); -TEST(FlBinaryMessengerTest, DeletingEngineClearsHandlers) { - FlEngine* engine = make_mock_engine(); FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(engine); - gboolean was_killed = FALSE; - // Listen for messages from the engine. - fl_binary_messenger_set_message_handler_on_channel(messenger, "test/messages", - message_cb, &was_killed, - kill_handler_notify_cb); + // Add handler to check the destroy_notify is called. + gboolean destroy_notify_called = FALSE; + fl_binary_messenger_set_message_handler_on_channel( + messenger, "test", + [](FlBinaryMessenger* messenger, const gchar* channel, GBytes* message, + FlBinaryMessengerResponseHandle* response_handle, + gpointer user_data) {}, + &destroy_notify_called, + [](gpointer user_data) { *static_cast(user_data) = TRUE; }); g_clear_object(&engine); - ASSERT_TRUE(was_killed); + ASSERT_TRUE(destroy_notify_called); } diff --git a/shell/platform/linux/testing/mock_engine.cc b/shell/platform/linux/testing/mock_engine.cc index 5db5d3704b397..b1806e8104653 100644 --- a/shell/platform/linux/testing/mock_engine.cc +++ b/shell/platform/linux/testing/mock_engine.cc @@ -96,56 +96,6 @@ struct _FlutterTaskRunner { namespace { -// Send a response from the engine. -static void send_response( - FLUTTER_API_SYMBOL(FlutterEngine) engine, - const std::string& channel, - const FlutterPlatformMessageResponseHandle* response_handle, - const uint8_t* message, - size_t message_size) { - if (response_handle == nullptr) { - return; - } - - FlutterTask task; - task.runner = new _FlutterTaskRunner(1234, channel, response_handle, message, - message_size); - task.task = task.runner->task; - engine->platform_post_task_callback(task, 0, engine->user_data); -} - -// Send a message from the engine. -static void send_message(FLUTTER_API_SYMBOL(FlutterEngine) engine, - const std::string& channel, - const uint8_t* message, - size_t message_size) { - FlutterTask task; - task.runner = - new _FlutterTaskRunner(1234, channel, nullptr, message, message_size); - task.task = task.runner->task; - engine->platform_post_task_callback(task, 0, engine->user_data); -} - -static void invoke_method(FLUTTER_API_SYMBOL(FlutterEngine) engine, - const std::string& channel, - const gchar* name, - FlValue* args) { - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(GError) error = nullptr; - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), name, args, &error); - EXPECT_NE(message, nullptr); - EXPECT_EQ(error, nullptr); - - FlutterTask task; - task.runner = new _FlutterTaskRunner( - 1234, channel, nullptr, - static_cast(g_bytes_get_data(message, nullptr)), - g_bytes_get_size(message)); - task.task = task.runner->task; - engine->platform_post_task_callback(task, 0, engine->user_data); -} - FlutterEngineResult FlutterEngineCreateAOTData( const FlutterEngineAOTDataSource* source, FlutterEngineAOTData* data_out) { @@ -247,117 +197,6 @@ FlutterEngineResult FlutterEngineSendPlatformMessage( const FlutterPlatformMessage* message) { EXPECT_TRUE(engine->running); - if (strcmp(message->channel, "test/echo") == 0) { - // Responds with the same message received. - send_response(engine, message->channel, message->response_handle, - message->message, message->message_size); - } else if (strcmp(message->channel, "test/send-message") == 0) { - // Triggers the engine to send a message. - send_response(engine, message->channel, message->response_handle, nullptr, - 0); - send_message(engine, "test/messages", message->message, - message->message_size); - } else if (strcmp(message->channel, "test/standard-method") == 0) { - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(GBytes) m = g_bytes_new(message->message, message->message_size); - g_autofree gchar* name = nullptr; - g_autoptr(FlValue) args = nullptr; - g_autoptr(GError) error = nullptr; - EXPECT_TRUE(fl_method_codec_decode_method_call(FL_METHOD_CODEC(codec), m, - &name, &args, &error)); - EXPECT_EQ(error, nullptr); - - g_autoptr(GBytes) response = nullptr; - if (strcmp(name, "Echo") == 0) { - // Returns args as a success result. - response = fl_method_codec_encode_success_envelope(FL_METHOD_CODEC(codec), - args, &error); - EXPECT_EQ(error, nullptr); - } else if (strcmp(name, "Error") == 0) { - // Returns an error result. - const gchar* code = nullptr; - const gchar* message = nullptr; - FlValue* details = nullptr; - if (fl_value_get_length(args) >= 2) { - FlValue* code_value = fl_value_get_list_value(args, 0); - EXPECT_EQ(fl_value_get_type(code_value), FL_VALUE_TYPE_STRING); - code = fl_value_get_string(code_value); - FlValue* message_value = fl_value_get_list_value(args, 1); - message = fl_value_get_type(message_value) == FL_VALUE_TYPE_STRING - ? fl_value_get_string(message_value) - : nullptr; - } - if (fl_value_get_length(args) >= 3) { - details = fl_value_get_list_value(args, 2); - } - response = fl_method_codec_encode_error_envelope( - FL_METHOD_CODEC(codec), code, message, details, &error); - EXPECT_EQ(error, nullptr); - } else if (strcmp(name, "InvokeMethod") == 0) { - // Gets the engine to call the shell. - if (fl_value_get_length(args) == 3) { - FlValue* channel_value = fl_value_get_list_value(args, 0); - EXPECT_EQ(fl_value_get_type(channel_value), FL_VALUE_TYPE_STRING); - const gchar* channel = fl_value_get_string(channel_value); - FlValue* name_value = fl_value_get_list_value(args, 1); - EXPECT_EQ(fl_value_get_type(name_value), FL_VALUE_TYPE_STRING); - const gchar* name = fl_value_get_string(name_value); - FlValue* method_args = fl_value_get_list_value(args, 2); - invoke_method(engine, channel, name, method_args); - } - response = fl_method_codec_encode_success_envelope(FL_METHOD_CODEC(codec), - nullptr, &error); - EXPECT_EQ(error, nullptr); - } else { - // Returns "not implemented". - response = g_bytes_new(nullptr, 0); - } - - send_response( - engine, message->channel, message->response_handle, - static_cast(g_bytes_get_data(response, nullptr)), - g_bytes_get_size(response)); - } else if (strcmp(message->channel, "test/nullptr-response") == 0) { - // Sends a null response. - send_response(engine, message->channel, message->response_handle, nullptr, - 0); - } else if (strcmp(message->channel, "test/failure") == 0) { - // Generates an internal error. - return kInternalInconsistency; - } else if (strcmp(message->channel, "test/key-event-handled") == 0 || - strcmp(message->channel, "test/key-event-not-handled") == 0) { - bool value = strcmp(message->channel, "test/key-event-handled") == 0; - g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - g_autoptr(FlValue) handledValue = fl_value_new_map(); - fl_value_set_string_take(handledValue, "handled", fl_value_new_bool(value)); - g_autoptr(GBytes) response = fl_message_codec_encode_message( - FL_MESSAGE_CODEC(codec), handledValue, nullptr); - send_response( - engine, message->channel, message->response_handle, - static_cast(g_bytes_get_data(response, nullptr)), - g_bytes_get_size(response)); - } else if (strcmp(message->channel, "test/key-event-delayed") == 0) { - static std::unique_ptr - delayed_response_handle = nullptr; - g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - g_autoptr(FlValue) handledValue = fl_value_new_map(); - fl_value_set_string_take(handledValue, "handled", fl_value_new_bool(true)); - g_autoptr(GBytes) response = fl_message_codec_encode_message( - FL_MESSAGE_CODEC(codec), handledValue, nullptr); - if (delayed_response_handle == nullptr) { - delayed_response_handle.reset(message->response_handle); - } else { - send_response( - engine, message->channel, message->response_handle, - static_cast(g_bytes_get_data(response, nullptr)), - g_bytes_get_size(response)); - send_response( - engine, message->channel, delayed_response_handle.release(), - static_cast(g_bytes_get_data(response, nullptr)), - g_bytes_get_size(response)); - } - } - return kSuccess; } @@ -401,11 +240,6 @@ FlutterEngineResult FlutterEngineSendPlatformMessageResponse( EXPECT_TRUE(engine->running); - // Send a message so the shell can check the responses received. - if (handle->channel != "test/responses") { - send_message(engine, "test/responses", data, data_length); - } - EXPECT_FALSE(handle->released); delete handle; From 449b6e7581e3ac15144e1d5883c04cb17585aa70 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Tue, 17 Dec 2024 08:18:51 +1300 Subject: [PATCH 2/2] Add note about why an empty buffer is not checked for value --- shell/platform/linux/fl_binary_messenger_test.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/platform/linux/fl_binary_messenger_test.cc b/shell/platform/linux/fl_binary_messenger_test.cc index 49d75a0f0fbef..3ea11fbcbc8bc 100644 --- a/shell/platform/linux/fl_binary_messenger_test.cc +++ b/shell/platform/linux/fl_binary_messenger_test.cc @@ -96,6 +96,8 @@ TEST(FlBinaryMessengerTest, SendNullptr) { called = true; EXPECT_STREQ(message->channel, "test"); + // Note we don't check message->message as it could be nullptr or a + // pointer to an buffer - either way it wouldn't be accessed. EXPECT_EQ(message->message_size, static_cast(0)); return kSuccess;