diff --git a/shell/platform/linux/fl_binary_messenger.cc b/shell/platform/linux/fl_binary_messenger.cc index 9d1403e054acf..ee01ff732e0b4 100644 --- a/shell/platform/linux/fl_binary_messenger.cc +++ b/shell/platform/linux/fl_binary_messenger.cc @@ -143,6 +143,18 @@ static void platform_message_handler_free(gpointer data) { g_free(self); } +static void engine_weak_notify_cb(gpointer user_data, + GObject* where_the_object_was) { + FlBinaryMessengerImpl* self = FL_BINARY_MESSENGER_IMPL(user_data); + + // Disconnect any handlers. + // Take the reference in case a handler tries to modify this table. + g_autoptr(GHashTable) handlers = self->platform_message_handlers; + self->platform_message_handlers = g_hash_table_new_full( + g_str_hash, g_str_equal, g_free, platform_message_handler_free); + g_hash_table_remove_all(handlers); +} + static gboolean fl_binary_messenger_platform_message_cb( FlEngine* engine, const gchar* channel, @@ -168,6 +180,14 @@ static gboolean fl_binary_messenger_platform_message_cb( static void fl_binary_messenger_impl_dispose(GObject* object) { FlBinaryMessengerImpl* self = FL_BINARY_MESSENGER_IMPL(object); + + { + g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine)); + if (engine) { + g_object_weak_unref(G_OBJECT(engine), engine_weak_notify_cb, self); + } + } + g_weak_ref_clear(&self->engine); g_clear_pointer(&self->platform_message_handlers, g_hash_table_unref); @@ -206,6 +226,13 @@ static void set_message_handler_on_channel( } } +static gboolean has_message_handler_on_channel(FlBinaryMessenger* messenger, + const gchar* channel) { + FlBinaryMessengerImpl* self = FL_BINARY_MESSENGER_IMPL(messenger); + return g_hash_table_contains(self->platform_message_handlers, + g_strdup(channel)); +} + gboolean do_unref(gpointer value) { g_object_unref(value); return G_SOURCE_REMOVE; @@ -302,6 +329,7 @@ static void fl_binary_messenger_impl_class_init( static void fl_binary_messenger_impl_iface_init( FlBinaryMessengerInterface* iface) { iface->set_message_handler_on_channel = set_message_handler_on_channel; + iface->has_message_handler_on_channel = has_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; @@ -322,6 +350,7 @@ FlBinaryMessenger* fl_binary_messenger_new(FlEngine* engine) { FL_IS_BINARY_MESSENGER_IMPL(self); g_weak_ref_init(&self->engine, G_OBJECT(engine)); + g_object_weak_ref(G_OBJECT(engine), engine_weak_notify_cb, self); fl_engine_set_platform_message_handler( engine, fl_binary_messenger_platform_message_cb, self, NULL); @@ -342,6 +371,16 @@ G_MODULE_EXPORT void fl_binary_messenger_set_message_handler_on_channel( self, channel, handler, user_data, destroy_notify); } +G_MODULE_EXPORT gboolean +fl_binary_messenger_has_message_handler_on_channel(FlBinaryMessenger* self, + const gchar* channel) { + g_return_val_if_fail(FL_IS_BINARY_MESSENGER(self), FALSE); + g_return_val_if_fail(channel != nullptr, FALSE); + + return FL_BINARY_MESSENGER_GET_IFACE(self)->has_message_handler_on_channel( + self, channel); +} + // Note: This function can be called from any thread. G_MODULE_EXPORT gboolean fl_binary_messenger_send_response( FlBinaryMessenger* self, diff --git a/shell/platform/linux/fl_binary_messenger_private.h b/shell/platform/linux/fl_binary_messenger_private.h index ce70c51dc61c6..fec30f1ae1ed3 100644 --- a/shell/platform/linux/fl_binary_messenger_private.h +++ b/shell/platform/linux/fl_binary_messenger_private.h @@ -22,6 +22,10 @@ G_BEGIN_DECLS */ FlBinaryMessenger* fl_binary_messenger_new(FlEngine* engine); +gboolean fl_binary_messenger_has_message_handler_on_channel( + FlBinaryMessenger* messenger, + const gchar* channel); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_BINARY_MESSENGER_PRIVATE_H_ diff --git a/shell/platform/linux/fl_binary_messenger_test.cc b/shell/platform/linux/fl_binary_messenger_test.cc index 2a4a3ce48e7d9..44bfa232715ad 100644 --- a/shell/platform/linux/fl_binary_messenger_test.cc +++ b/shell/platform/linux/fl_binary_messenger_test.cc @@ -460,3 +460,21 @@ TEST(FlBinaryMessengerTest, RespondOnBackgroundThread) { // Blocks here until response_cb is called. g_main_loop_run(loop); } + +TEST(FlBinaryMessengerTest, DeletingEngineClearsHandlers) { + 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); + + ASSERT_TRUE(fl_binary_messenger_has_message_handler_on_channel( + messenger, "test/messages")); + + g_object_unref(engine); + engine = nullptr; + + ASSERT_FALSE(fl_binary_messenger_has_message_handler_on_channel( + messenger, "test/messages")); +} diff --git a/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h b/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h index 0fa7d9980fc44..7f94551afdad7 100644 --- a/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h +++ b/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h @@ -73,6 +73,9 @@ struct _FlBinaryMessengerInterface { gpointer user_data, GDestroyNotify destroy_notify); + gboolean (*has_message_handler_on_channel)(FlBinaryMessenger* messenger, + const gchar* channel); + gboolean (*send_response)(FlBinaryMessenger* messenger, FlBinaryMessengerResponseHandle* response_handle, GBytes* response,