Flutter Engine
The Flutter Engine
fl_method_channel.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h"
6
7#include <gmodule.h>
8
9#include "flutter/shell/platform/linux/fl_method_call_private.h"
10#include "flutter/shell/platform/linux/fl_method_channel_private.h"
11#include "flutter/shell/platform/linux/fl_method_codec_private.h"
12
15
16 // Messenger to communicate on.
17 FlBinaryMessenger* messenger;
18
19 // TRUE if the channel has been closed.
21
22 // Channel name.
23 gchar* name;
24
25 // Codec to en/decode messages.
26 FlMethodCodec* codec;
27
28 // Function called when a method call is received.
29 FlMethodChannelMethodCallHandler method_call_handler;
32};
33
34G_DEFINE_TYPE(FlMethodChannel, fl_method_channel, G_TYPE_OBJECT)
35
36// Called when a binary message is received on this channel.
37static void message_cb(FlBinaryMessenger* messenger,
38 const gchar* channel,
39 GBytes* message,
40 FlBinaryMessengerResponseHandle* response_handle,
41 gpointer user_data) {
42 FlMethodChannel* self = FL_METHOD_CHANNEL(user_data);
43
44 if (self->method_call_handler == nullptr) {
45 return;
46 }
47
48 g_autofree gchar* method = nullptr;
49 g_autoptr(FlValue) args = nullptr;
50 g_autoptr(GError) error = nullptr;
52 &error)) {
53 g_warning("Failed to decode method call: %s", error->message);
54 return;
55 }
56
57 g_autoptr(FlMethodCall) method_call =
58 fl_method_call_new(method, args, self, response_handle);
59 self->method_call_handler(self, method_call, self->method_call_handler_data);
60}
61
62// Called when a response is received to a sent message.
63static void message_response_cb(GObject* object,
64 GAsyncResult* result,
65 gpointer user_data) {
66 GTask* task = G_TASK(user_data);
67 g_task_return_pointer(task, result, g_object_unref);
68}
69
70// Called when the channel handler is closed.
71static void channel_closed_cb(gpointer user_data) {
72 g_autoptr(FlMethodChannel) self = FL_METHOD_CHANNEL(user_data);
73
74 self->channel_closed = TRUE;
75
76 // Disconnect handler.
77 if (self->method_call_handler_destroy_notify != nullptr) {
78 self->method_call_handler_destroy_notify(self->method_call_handler_data);
79 }
80 self->method_call_handler = nullptr;
81 self->method_call_handler_data = nullptr;
82 self->method_call_handler_destroy_notify = nullptr;
83}
84
85static void fl_method_channel_dispose(GObject* object) {
86 FlMethodChannel* self = FL_METHOD_CHANNEL(object);
87
88 // Note we don't have to clear the handler in messenger as it holds
89 // a reference to this object so the following code is only run after
90 // the messenger has closed the channel already.
91
92 g_clear_object(&self->messenger);
93 g_clear_pointer(&self->name, g_free);
94 g_clear_object(&self->codec);
95
96 if (self->method_call_handler_destroy_notify != nullptr) {
97 self->method_call_handler_destroy_notify(self->method_call_handler_data);
98 }
99 self->method_call_handler = nullptr;
100 self->method_call_handler_data = nullptr;
101 self->method_call_handler_destroy_notify = nullptr;
102
103 G_OBJECT_CLASS(fl_method_channel_parent_class)->dispose(object);
104}
105
106static void fl_method_channel_class_init(FlMethodChannelClass* klass) {
107 G_OBJECT_CLASS(klass)->dispose = fl_method_channel_dispose;
108}
109
110static void fl_method_channel_init(FlMethodChannel* self) {}
111
112G_MODULE_EXPORT FlMethodChannel* fl_method_channel_new(
113 FlBinaryMessenger* messenger,
114 const gchar* name,
115 FlMethodCodec* codec) {
116 g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
117 g_return_val_if_fail(name != nullptr, nullptr);
118 g_return_val_if_fail(FL_IS_METHOD_CODEC(codec), nullptr);
119
120 FlMethodChannel* self =
121 FL_METHOD_CHANNEL(g_object_new(fl_method_channel_get_type(), nullptr));
122
123 self->messenger = FL_BINARY_MESSENGER(g_object_ref(messenger));
124 self->name = g_strdup(name);
125 self->codec = FL_METHOD_CODEC(g_object_ref(codec));
126
128 self->messenger, self->name, message_cb, g_object_ref(self),
130
131 return self;
132}
133
135 FlMethodChannel* self,
136 FlMethodChannelMethodCallHandler handler,
137 gpointer user_data,
138 GDestroyNotify destroy_notify) {
139 g_return_if_fail(FL_IS_METHOD_CHANNEL(self));
140
141 // Don't set handler if channel closed.
142 if (self->channel_closed) {
143 if (handler != nullptr) {
144 g_warning(
145 "Attempted to set method call handler on a closed FlMethodChannel");
146 }
147 if (destroy_notify != nullptr) {
148 destroy_notify(user_data);
149 }
150 return;
151 }
152
153 if (self->method_call_handler_destroy_notify != nullptr) {
154 self->method_call_handler_destroy_notify(self->method_call_handler_data);
155 }
156
157 self->method_call_handler = handler;
158 self->method_call_handler_data = user_data;
159 self->method_call_handler_destroy_notify = destroy_notify;
160}
161
163 FlMethodChannel* self,
164 const gchar* method,
165 FlValue* args,
166 GCancellable* cancellable,
167 GAsyncReadyCallback callback,
168 gpointer user_data) {
169 g_return_if_fail(FL_IS_METHOD_CHANNEL(self));
170 g_return_if_fail(method != nullptr);
171
172 g_autoptr(GTask) task =
173 callback != nullptr ? g_task_new(self, cancellable, callback, user_data)
174 : nullptr;
175
176 g_autoptr(GError) error = nullptr;
177 g_autoptr(GBytes) message =
179 if (message == nullptr) {
180 if (task != nullptr) {
181 g_task_return_error(task, error);
182 }
183 return;
184 }
185
187 self->messenger, self->name, message, cancellable,
188 callback != nullptr ? message_response_cb : nullptr,
189 g_steal_pointer(&task));
190}
191
192G_MODULE_EXPORT FlMethodResponse* fl_method_channel_invoke_method_finish(
193 FlMethodChannel* self,
194 GAsyncResult* result,
195 GError** error) {
196 g_return_val_if_fail(FL_IS_METHOD_CHANNEL(self), nullptr);
197 g_return_val_if_fail(g_task_is_valid(result, self), nullptr);
198
199 g_autoptr(GTask) task = G_TASK(result);
200 GAsyncResult* r = G_ASYNC_RESULT(g_task_propagate_pointer(task, nullptr));
201
202 g_autoptr(GBytes) response =
204 if (response == nullptr) {
205 return nullptr;
206 }
207
208 return fl_method_codec_decode_response(self->codec, response, error);
209}
210
212 FlMethodChannel* self,
213 FlBinaryMessengerResponseHandle* response_handle,
214 FlMethodResponse* response,
215 GError** error) {
216 g_return_val_if_fail(FL_IS_METHOD_CHANNEL(self), FALSE);
217 g_return_val_if_fail(FL_IS_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle),
218 FALSE);
219 g_return_val_if_fail(FL_IS_METHOD_SUCCESS_RESPONSE(response) ||
220 FL_IS_METHOD_ERROR_RESPONSE(response) ||
221 FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response),
222 FALSE);
223
224 g_autoptr(GBytes) message = nullptr;
225 if (FL_IS_METHOD_SUCCESS_RESPONSE(response)) {
226 FlMethodSuccessResponse* r = FL_METHOD_SUCCESS_RESPONSE(response);
229 if (message == nullptr) {
230 return FALSE;
231 }
232 } else if (FL_IS_METHOD_ERROR_RESPONSE(response)) {
233 FlMethodErrorResponse* r = FL_METHOD_ERROR_RESPONSE(response);
238 if (message == nullptr) {
239 return FALSE;
240 }
241 } else if (FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response)) {
242 message = nullptr;
243 } else {
244 g_assert_not_reached();
245 }
246
247 return fl_binary_messenger_send_response(self->messenger, response_handle,
248 message, error);
249}
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle, fl_basic_message_channel_response_handle, G_TYPE_OBJECT) static void fl_basic_message_channel_response_handle_dispose(GObject *object)
G_MODULE_EXPORT GBytes * fl_binary_messenger_send_on_channel_finish(FlBinaryMessenger *self, GAsyncResult *result, GError **error)
G_MODULE_EXPORT void fl_binary_messenger_set_message_handler_on_channel(FlBinaryMessenger *self, const gchar *channel, FlBinaryMessengerMessageHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
G_MODULE_EXPORT void fl_binary_messenger_send_on_channel(FlBinaryMessenger *self, const gchar *channel, GBytes *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
G_MODULE_EXPORT gboolean fl_binary_messenger_send_response(FlBinaryMessenger *self, FlBinaryMessengerResponseHandle *response_handle, GBytes *response, GError **error)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlMethodCall * fl_method_call_new(const gchar *name, FlValue *args, FlMethodChannel *channel, FlBinaryMessengerResponseHandle *response_handle)
static void message_cb(FlBinaryMessenger *messenger, const gchar *channel, GBytes *message, FlBinaryMessengerResponseHandle *response_handle, gpointer user_data)
static void fl_method_channel_class_init(FlMethodChannelClass *klass)
static void fl_method_channel_init(FlMethodChannel *self)
G_MODULE_EXPORT FlMethodResponse * fl_method_channel_invoke_method_finish(FlMethodChannel *self, GAsyncResult *result, GError **error)
G_MODULE_EXPORT FlMethodChannel * fl_method_channel_new(FlBinaryMessenger *messenger, const gchar *name, FlMethodCodec *codec)
G_MODULE_EXPORT void fl_method_channel_invoke_method(FlMethodChannel *self, const gchar *method, FlValue *args, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
static void message_response_cb(GObject *object, GAsyncResult *result, gpointer user_data)
gboolean fl_method_channel_respond(FlMethodChannel *self, FlBinaryMessengerResponseHandle *response_handle, FlMethodResponse *response, GError **error)
static void fl_method_channel_dispose(GObject *object)
static void channel_closed_cb(gpointer user_data)
G_MODULE_EXPORT void fl_method_channel_set_method_call_handler(FlMethodChannel *self, FlMethodChannelMethodCallHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
G_BEGIN_DECLS G_MODULE_EXPORT FlMethodCall * method_call
FlMethodResponse * fl_method_codec_decode_response(FlMethodCodec *self, GBytes *message, GError **error)
gboolean fl_method_codec_decode_method_call(FlMethodCodec *self, GBytes *message, gchar **name, FlValue **args, GError **error)
GBytes * fl_method_codec_encode_success_envelope(FlMethodCodec *self, FlValue *result, GError **error)
GBytes * fl_method_codec_encode_method_call(FlMethodCodec *self, const gchar *name, FlValue *args, GError **error)
GBytes * fl_method_codec_encode_error_envelope(FlMethodCodec *self, const gchar *code, const gchar *message, FlValue *details, GError **error)
G_MODULE_EXPORT FlValue * fl_method_success_response_get_result(FlMethodSuccessResponse *self)
G_MODULE_EXPORT const gchar * fl_method_error_response_get_message(FlMethodErrorResponse *self)
G_MODULE_EXPORT FlValue * fl_method_error_response_get_details(FlMethodErrorResponse *self)
G_MODULE_EXPORT const gchar * fl_method_error_response_get_code(FlMethodErrorResponse *self)
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:42
Win32Message message
return FALSE
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
FlMethodChannelMethodCallHandler method_call_handler
FlBinaryMessenger * messenger
FlMethodCodec * codec
GDestroyNotify method_call_handler_destroy_notify
gpointer method_call_handler_data
void * user_data