mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Make FlBasicMessageChannelResponseHandle a GObject to detect unresponded and double responded messages. (flutter/engine#18514)
This commit is contained in:
parent
df5615108f
commit
7b4840a4fc
@ -23,33 +23,51 @@ struct _FlBasicMessageChannel {
|
||||
gpointer message_handler_data;
|
||||
};
|
||||
|
||||
// Wrap the binary messenger handle for type safety and to make the API
|
||||
// consistent
|
||||
struct _FlBasicMessageChannelResponseHandle {
|
||||
GObject parent_instance;
|
||||
|
||||
FlBinaryMessengerResponseHandle* response_handle;
|
||||
};
|
||||
|
||||
static FlBasicMessageChannelResponseHandle* response_handle_new(
|
||||
FlBinaryMessengerResponseHandle* response_handle) {
|
||||
FlBasicMessageChannelResponseHandle* handle =
|
||||
static_cast<FlBasicMessageChannelResponseHandle*>(
|
||||
g_malloc0(sizeof(FlBasicMessageChannelResponseHandle)));
|
||||
handle->response_handle = response_handle;
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void response_handle_free(FlBasicMessageChannelResponseHandle* handle) {
|
||||
g_free(handle);
|
||||
}
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(FlBasicMessageChannelResponseHandle,
|
||||
response_handle_free);
|
||||
|
||||
// Added here to stop the compiler from optimising this function away
|
||||
G_MODULE_EXPORT GType fl_basic_message_channel_get_type();
|
||||
|
||||
G_DEFINE_TYPE(FlBasicMessageChannel, fl_basic_message_channel, G_TYPE_OBJECT)
|
||||
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle,
|
||||
fl_basic_message_channel_response_handle,
|
||||
G_TYPE_OBJECT)
|
||||
|
||||
static void fl_basic_message_channel_response_handle_dispose(GObject* object) {
|
||||
FlBasicMessageChannelResponseHandle* self =
|
||||
FL_BASIC_MESSAGE_CHANNEL_RESPONSE_HANDLE(object);
|
||||
|
||||
g_clear_object(&self->response_handle);
|
||||
|
||||
G_OBJECT_CLASS(fl_basic_message_channel_response_handle_parent_class)
|
||||
->dispose(object);
|
||||
}
|
||||
|
||||
static void fl_basic_message_channel_response_handle_class_init(
|
||||
FlBasicMessageChannelResponseHandleClass* klass) {
|
||||
G_OBJECT_CLASS(klass)->dispose =
|
||||
fl_basic_message_channel_response_handle_dispose;
|
||||
}
|
||||
|
||||
static void fl_basic_message_channel_response_handle_init(
|
||||
FlBasicMessageChannelResponseHandle* self) {}
|
||||
|
||||
static FlBasicMessageChannelResponseHandle*
|
||||
fl_basic_message_channel_response_handle_new(
|
||||
FlBinaryMessengerResponseHandle* response_handle) {
|
||||
FlBasicMessageChannelResponseHandle* self =
|
||||
FL_BASIC_MESSAGE_CHANNEL_RESPONSE_HANDLE(g_object_new(
|
||||
fl_basic_message_channel_response_handle_get_type(), nullptr));
|
||||
|
||||
self->response_handle =
|
||||
FL_BINARY_MESSENGER_RESPONSE_HANDLE(g_object_ref(response_handle));
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// Called when a binary message is received on this channel
|
||||
static void message_cb(FlBinaryMessenger* messenger,
|
||||
@ -74,8 +92,9 @@ static void message_cb(FlBinaryMessenger* messenger,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
self->message_handler(self, message_value,
|
||||
response_handle_new(response_handle),
|
||||
g_autoptr(FlBasicMessageChannelResponseHandle) handle =
|
||||
fl_basic_message_channel_response_handle_new(response_handle);
|
||||
self->message_handler(self, message_value, handle,
|
||||
self->message_handler_data);
|
||||
}
|
||||
|
||||
@ -146,18 +165,18 @@ G_MODULE_EXPORT gboolean fl_basic_message_channel_respond(
|
||||
GError** error) {
|
||||
g_return_val_if_fail(FL_IS_BASIC_MESSAGE_CHANNEL(self), FALSE);
|
||||
g_return_val_if_fail(response_handle != nullptr, FALSE);
|
||||
|
||||
// Take reference to ensure it is freed
|
||||
g_autoptr(FlBasicMessageChannelResponseHandle) owned_response_handle =
|
||||
response_handle;
|
||||
g_return_val_if_fail(response_handle->response_handle != nullptr, FALSE);
|
||||
|
||||
g_autoptr(GBytes) data =
|
||||
fl_message_codec_encode_message(self->codec, message, error);
|
||||
if (data == nullptr)
|
||||
return FALSE;
|
||||
|
||||
return fl_binary_messenger_send_response(
|
||||
self->messenger, owned_response_handle->response_handle, data, error);
|
||||
gboolean result = fl_binary_messenger_send_response(
|
||||
self->messenger, response_handle->response_handle, data, error);
|
||||
g_clear_object(&response_handle->response_handle);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void fl_basic_message_channel_send(FlBasicMessageChannel* self,
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
|
||||
#include <gmodule.h>
|
||||
|
||||
G_DEFINE_QUARK(fl_binary_messenger_codec_error_quark,
|
||||
fl_binary_messenger_codec_error)
|
||||
|
||||
struct _FlBinaryMessenger {
|
||||
GObject parent_instance;
|
||||
|
||||
@ -21,12 +24,61 @@ struct _FlBinaryMessenger {
|
||||
|
||||
G_DEFINE_TYPE(FlBinaryMessenger, fl_binary_messenger, G_TYPE_OBJECT)
|
||||
|
||||
struct _FlBinaryMessengerResponseHandle {
|
||||
GObject parent_instance;
|
||||
|
||||
// Messenger sending response on
|
||||
FlBinaryMessenger* messenger;
|
||||
|
||||
// Handle to send the response with. This is cleared to nullptr when it is
|
||||
// used.
|
||||
const FlutterPlatformMessageResponseHandle* response_handle;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(FlBinaryMessengerResponseHandle,
|
||||
fl_binary_messenger_response_handle,
|
||||
G_TYPE_OBJECT)
|
||||
|
||||
static void fl_binary_messenger_response_handle_dispose(GObject* object) {
|
||||
FlBinaryMessengerResponseHandle* self =
|
||||
FL_BINARY_MESSENGER_RESPONSE_HANDLE(object);
|
||||
|
||||
if (self->response_handle != nullptr && self->messenger->engine != nullptr)
|
||||
g_critical("FlBinaryMessengerResponseHandle was not responded to");
|
||||
|
||||
g_clear_object(&self->messenger);
|
||||
self->response_handle = nullptr;
|
||||
|
||||
G_OBJECT_CLASS(fl_binary_messenger_response_handle_parent_class)
|
||||
->dispose(object);
|
||||
}
|
||||
|
||||
static void fl_binary_messenger_response_handle_class_init(
|
||||
FlBinaryMessengerResponseHandleClass* klass) {
|
||||
G_OBJECT_CLASS(klass)->dispose = fl_binary_messenger_response_handle_dispose;
|
||||
}
|
||||
|
||||
static void fl_binary_messenger_response_handle_init(
|
||||
FlBinaryMessengerResponseHandle* self) {}
|
||||
|
||||
static FlBinaryMessengerResponseHandle* fl_binary_messenger_response_handle_new(
|
||||
FlBinaryMessenger* messenger,
|
||||
const FlutterPlatformMessageResponseHandle* response_handle) {
|
||||
FlBinaryMessengerResponseHandle* self = FL_BINARY_MESSENGER_RESPONSE_HANDLE(
|
||||
g_object_new(fl_binary_messenger_response_handle_get_type(), nullptr));
|
||||
|
||||
self->messenger = FL_BINARY_MESSENGER(g_object_ref(messenger));
|
||||
self->response_handle = response_handle;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
FlBinaryMessengerMessageHandler message_handler;
|
||||
gpointer message_handler_data;
|
||||
} PlatformMessageHandler;
|
||||
|
||||
PlatformMessageHandler* platform_message_handler_new(
|
||||
static PlatformMessageHandler* platform_message_handler_new(
|
||||
FlBinaryMessengerMessageHandler handler,
|
||||
gpointer user_data) {
|
||||
PlatformMessageHandler* self = static_cast<PlatformMessageHandler*>(
|
||||
@ -36,32 +88,11 @@ PlatformMessageHandler* platform_message_handler_new(
|
||||
return self;
|
||||
}
|
||||
|
||||
void platform_message_handler_free(gpointer data) {
|
||||
static void platform_message_handler_free(gpointer data) {
|
||||
PlatformMessageHandler* self = static_cast<PlatformMessageHandler*>(data);
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
struct _FlBinaryMessengerResponseHandle {
|
||||
const FlutterPlatformMessageResponseHandle* response_handle;
|
||||
};
|
||||
|
||||
static FlBinaryMessengerResponseHandle* response_handle_new(
|
||||
const FlutterPlatformMessageResponseHandle* response_handle) {
|
||||
FlBinaryMessengerResponseHandle* self =
|
||||
static_cast<FlBinaryMessengerResponseHandle*>(
|
||||
g_malloc0(sizeof(FlBinaryMessengerResponseHandle)));
|
||||
self->response_handle = response_handle;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static void response_handle_free(FlBinaryMessengerResponseHandle* self) {
|
||||
g_free(self);
|
||||
}
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(FlBinaryMessengerResponseHandle,
|
||||
response_handle_free);
|
||||
|
||||
static void engine_weak_notify_cb(gpointer user_data, GObject* object) {
|
||||
FlBinaryMessenger* self = FL_BINARY_MESSENGER(user_data);
|
||||
self->engine = nullptr;
|
||||
@ -75,14 +106,13 @@ static gboolean fl_binary_messenger_platform_message_cb(
|
||||
void* user_data) {
|
||||
FlBinaryMessenger* self = FL_BINARY_MESSENGER(user_data);
|
||||
|
||||
FlBinaryMessengerResponseHandle* handle =
|
||||
response_handle_new(response_handle);
|
||||
|
||||
PlatformMessageHandler* handler = static_cast<PlatformMessageHandler*>(
|
||||
g_hash_table_lookup(self->platform_message_handlers, channel));
|
||||
if (handler == nullptr)
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(FlBinaryMessengerResponseHandle) handle =
|
||||
fl_binary_messenger_response_handle_new(self, response_handle);
|
||||
handler->message_handler(self, channel, message, handle,
|
||||
handler->message_handler_data);
|
||||
|
||||
@ -148,16 +178,23 @@ G_MODULE_EXPORT gboolean fl_binary_messenger_send_response(
|
||||
GError** error) {
|
||||
g_return_val_if_fail(FL_IS_BINARY_MESSENGER(self), FALSE);
|
||||
g_return_val_if_fail(response_handle != nullptr, FALSE);
|
||||
|
||||
// Take reference to ensure it is freed
|
||||
g_autoptr(FlBinaryMessengerResponseHandle) owned_response_handle =
|
||||
response_handle;
|
||||
g_return_val_if_fail(response_handle->messenger == self, FALSE);
|
||||
g_return_val_if_fail(response_handle->response_handle != nullptr, FALSE);
|
||||
|
||||
if (self->engine == nullptr)
|
||||
return TRUE;
|
||||
|
||||
if (response_handle->response_handle == nullptr) {
|
||||
g_set_error(
|
||||
error, FL_BINARY_MESSENGER_ERROR,
|
||||
FL_BINARY_MESSENGER_ERROR_ALREADY_RESPONDED,
|
||||
"Attempted to respond to a message that is already responded to");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean result = fl_engine_send_platform_message_response(
|
||||
self->engine, owned_response_handle->response_handle, response, error);
|
||||
self->engine, response_handle->response_handle, response, error);
|
||||
response_handle->response_handle = nullptr;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -23,6 +23,12 @@ G_DECLARE_FINAL_TYPE(FlBasicMessageChannel,
|
||||
BASIC_MESSAGE_CHANNEL,
|
||||
GObject)
|
||||
|
||||
G_DECLARE_FINAL_TYPE(FlBasicMessageChannelResponseHandle,
|
||||
fl_basic_message_channel_response_handle,
|
||||
FL,
|
||||
BASIC_MESSAGE_CHANNEL_RESPONSE_HANDLE,
|
||||
GObject)
|
||||
|
||||
/**
|
||||
* FlBasicMessageChannel:
|
||||
*
|
||||
@ -79,19 +85,23 @@ G_DECLARE_FINAL_TYPE(FlBasicMessageChannel,
|
||||
/**
|
||||
* FlBasicMessageChannelResponseHandle:
|
||||
*
|
||||
* A handle used to respond to messages.
|
||||
* #FlBasicMessageChannelResponseHandle is an object used to send responses
|
||||
* with.
|
||||
*/
|
||||
typedef struct _FlBasicMessageChannelResponseHandle
|
||||
FlBasicMessageChannelResponseHandle;
|
||||
|
||||
/**
|
||||
* FlBasicMessageChannelMessageHandler:
|
||||
* @channel: an #FlBasicMessageChannel.
|
||||
* @message: message received.
|
||||
* @response_handle: (transfer full): a handle to respond to the message with.
|
||||
* @response_handle: a handle to respond to the message with.
|
||||
* @user_data: (closure): data provided when registering this handler.
|
||||
*
|
||||
* Function called when a message is received.
|
||||
* Function called when a message is received. Call
|
||||
* fl_basic_message_channel_respond() to respond to this message. If the
|
||||
* response is not occurring in this callback take a reference to
|
||||
* @response_handle and release that once it has been responded to. Failing to
|
||||
* respond before the last reference to @response_handle is dropped is a
|
||||
* programming error.
|
||||
*/
|
||||
typedef void (*FlBasicMessageChannelMessageHandler)(
|
||||
FlBasicMessageChannel* channel,
|
||||
@ -132,7 +142,7 @@ void fl_basic_message_channel_set_message_handler(
|
||||
/**
|
||||
* fl_basic_message_channel_respond:
|
||||
* @channel: an #FlBasicMessageChannel.
|
||||
* @response_handle: (transfer full): handle that was provided in a
|
||||
* @response_handle: handle that was provided in a
|
||||
* #FlBasicMessageChannelMessageHandler.
|
||||
* @message: (allow-none): message response to send or %NULL for an empty
|
||||
* response.
|
||||
|
||||
@ -14,12 +14,33 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* FlBinaryMessengerError:
|
||||
* @FL_BINARY_MESSENGER_ERROR_ALREADY_RESPONDED: unable to send response, this
|
||||
* message has already been responded to.
|
||||
*
|
||||
* Errors for #FlBinaryMessenger objects to set on failures.
|
||||
*/
|
||||
#define FL_BINARY_MESSENGER_ERROR fl_binary_messenger_codec_error_quark()
|
||||
|
||||
typedef enum {
|
||||
FL_BINARY_MESSENGER_ERROR_ALREADY_RESPONDED,
|
||||
} FlBinaryMessengerError;
|
||||
|
||||
GQuark fl_binary_messenger_codec_error_quark(void) G_GNUC_CONST;
|
||||
|
||||
G_DECLARE_FINAL_TYPE(FlBinaryMessenger,
|
||||
fl_binary_messenger,
|
||||
FL,
|
||||
BINARY_MESSENGER,
|
||||
GObject)
|
||||
|
||||
G_DECLARE_FINAL_TYPE(FlBinaryMessengerResponseHandle,
|
||||
fl_binary_messenger_response_handle,
|
||||
FL,
|
||||
BINARY_MESSENGER_RESPONSE_HANDLE,
|
||||
GObject)
|
||||
|
||||
/**
|
||||
* FlBinaryMessenger:
|
||||
*
|
||||
@ -30,20 +51,23 @@ G_DECLARE_FINAL_TYPE(FlBinaryMessenger,
|
||||
/**
|
||||
* FlBinaryMessengerResponseHandle:
|
||||
*
|
||||
* A handle used to respond to platform messages.
|
||||
* #FlBinaryMessengerResponseHandle is an object used to send responses with.
|
||||
*/
|
||||
typedef struct _FlBinaryMessengerResponseHandle FlBinaryMessengerResponseHandle;
|
||||
|
||||
/**
|
||||
* FlBinaryMessengerMessageHandler:
|
||||
* @messenger: an #FlBinaryMessenger.
|
||||
* @channel: channel message received on.
|
||||
* @message: message content received from Dart.
|
||||
* @response_handle: (transfer full): a handle to respond to the message with.
|
||||
* @response_handle: a handle to respond to the message with.
|
||||
* @user_data: (closure): data provided when registering this handler.
|
||||
*
|
||||
* Function called when platform messages are received. The receiver must
|
||||
* call fl_binary_messenger_send_response() to avoid leaking the handle.
|
||||
* Function called when platform messages are received. Call
|
||||
* fl_binary_messenger_send_response() to respond to this message. If the
|
||||
* response is not occurring in this callback take a reference to
|
||||
* @response_handle and release that once it has been responded to. Failing to
|
||||
* respond before the last reference to @response_handle is dropped is a
|
||||
* programming error.
|
||||
*/
|
||||
typedef void (*FlBinaryMessengerMessageHandler)(
|
||||
FlBinaryMessenger* messenger,
|
||||
@ -74,7 +98,7 @@ void fl_binary_messenger_set_message_handler_on_channel(
|
||||
/**
|
||||
* fl_binary_messenger_send_response:
|
||||
* @binary_messenger: an #FlBinaryMessenger.
|
||||
* @response_handle: (transfer full): handle that was provided in a
|
||||
* @response_handle: handle that was provided in a
|
||||
* #FlBinaryMessengerMessageHandler.
|
||||
* @response: (allow-none): response to send or %NULL for an empty response.
|
||||
* @error: (allow-none): #GError location to store the error occurring, or %NULL
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user