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 
14  GObject parent_instance;
15 
16  // Messenger to communicate on.
17  FlBinaryMessenger* messenger;
18 
19  // TRUE if the channel has been closed.
20  gboolean channel_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 
34 // Added here to stop the compiler from optimizing this function away.
35 G_MODULE_EXPORT GType fl_method_channel_get_type();
36 
37 G_DEFINE_TYPE(FlMethodChannel, fl_method_channel, G_TYPE_OBJECT)
38 
39 // Called when a binary message is received on this channel.
40 static void message_cb(FlBinaryMessenger* messenger,
41  const gchar* channel,
42  GBytes* message,
43  FlBinaryMessengerResponseHandle* response_handle,
44  gpointer user_data) {
45  FlMethodChannel* self = FL_METHOD_CHANNEL(user_data);
46 
47  if (self->method_call_handler == nullptr) {
48  return;
49  }
50 
51  g_autofree gchar* method = nullptr;
52  g_autoptr(FlValue) args = nullptr;
53  g_autoptr(GError) error = nullptr;
54  if (!fl_method_codec_decode_method_call(self->codec, message, &method, &args,
55  &error)) {
56  g_warning("Failed to decode method call: %s", error->message);
57  return;
58  }
59 
60  g_autoptr(FlMethodCall) method_call =
61  fl_method_call_new(method, args, self, response_handle);
62  self->method_call_handler(self, method_call, self->method_call_handler_data);
63 }
64 
65 // Called when a response is received to a sent message.
66 static void message_response_cb(GObject* object,
67  GAsyncResult* result,
68  gpointer user_data) {
69  GTask* task = G_TASK(user_data);
70  g_task_return_pointer(task, result, g_object_unref);
71 }
72 
73 // Called when the channel handler is closed.
74 static void channel_closed_cb(gpointer user_data) {
75  g_autoptr(FlMethodChannel) self = FL_METHOD_CHANNEL(user_data);
76 
77  self->channel_closed = TRUE;
78  // Clear the messenger so that disposing the channel will not clear the
79  // messenger's mapped channel, since `channel_closed_cb` means the messenger
80  // has abandoned this channel.
81  self->messenger = nullptr;
82 
83  // Disconnect handler.
84  if (self->method_call_handler_destroy_notify != nullptr) {
85  self->method_call_handler_destroy_notify(self->method_call_handler_data);
86  }
87  self->method_call_handler = nullptr;
88  self->method_call_handler_data = nullptr;
89  self->method_call_handler_destroy_notify = nullptr;
90 }
91 
92 static void fl_method_channel_dispose(GObject* object) {
93  FlMethodChannel* self = FL_METHOD_CHANNEL(object);
94 
95  if (self->messenger != nullptr) {
97  self->messenger, self->name, nullptr, nullptr, nullptr);
98  }
99 
100  g_clear_object(&self->messenger);
101  g_clear_pointer(&self->name, g_free);
102  g_clear_object(&self->codec);
103 
104  if (self->method_call_handler_destroy_notify != nullptr) {
105  self->method_call_handler_destroy_notify(self->method_call_handler_data);
106  }
107  self->method_call_handler = nullptr;
108  self->method_call_handler_data = nullptr;
109  self->method_call_handler_destroy_notify = nullptr;
110 
111  G_OBJECT_CLASS(fl_method_channel_parent_class)->dispose(object);
112 }
113 
114 static void fl_method_channel_class_init(FlMethodChannelClass* klass) {
115  G_OBJECT_CLASS(klass)->dispose = fl_method_channel_dispose;
116 }
117 
118 static void fl_method_channel_init(FlMethodChannel* self) {}
119 
120 G_MODULE_EXPORT FlMethodChannel* fl_method_channel_new(
121  FlBinaryMessenger* messenger,
122  const gchar* name,
123  FlMethodCodec* codec) {
124  g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
125  g_return_val_if_fail(name != nullptr, nullptr);
126  g_return_val_if_fail(FL_IS_METHOD_CODEC(codec), nullptr);
127 
128  FlMethodChannel* self =
129  FL_METHOD_CHANNEL(g_object_new(fl_method_channel_get_type(), nullptr));
130 
131  self->messenger = FL_BINARY_MESSENGER(g_object_ref(messenger));
132  self->name = g_strdup(name);
133  self->codec = FL_METHOD_CODEC(g_object_ref(codec));
134 
136  self->messenger, self->name, message_cb, g_object_ref(self),
138 
139  return self;
140 }
141 
143  FlMethodChannel* self,
144  FlMethodChannelMethodCallHandler handler,
145  gpointer user_data,
146  GDestroyNotify destroy_notify) {
147  g_return_if_fail(FL_IS_METHOD_CHANNEL(self));
148 
149  // Don't set handler if channel closed.
150  if (self->channel_closed) {
151  if (handler != nullptr) {
152  g_warning(
153  "Attempted to set method call handler on a closed FlMethodChannel");
154  }
155  if (destroy_notify != nullptr) {
156  destroy_notify(user_data);
157  }
158  return;
159  }
160 
161  if (self->method_call_handler_destroy_notify != nullptr) {
162  self->method_call_handler_destroy_notify(self->method_call_handler_data);
163  }
164 
165  self->method_call_handler = handler;
166  self->method_call_handler_data = user_data;
167  self->method_call_handler_destroy_notify = destroy_notify;
168 }
169 
170 G_MODULE_EXPORT void fl_method_channel_invoke_method(
171  FlMethodChannel* self,
172  const gchar* method,
173  FlValue* args,
174  GCancellable* cancellable,
175  GAsyncReadyCallback callback,
176  gpointer user_data) {
177  g_return_if_fail(FL_IS_METHOD_CHANNEL(self));
178  g_return_if_fail(method != nullptr);
179 
180  g_autoptr(GTask) task =
181  callback != nullptr ? g_task_new(self, cancellable, callback, user_data)
182  : nullptr;
183 
184  g_autoptr(GError) error = nullptr;
185  g_autoptr(GBytes) message =
186  fl_method_codec_encode_method_call(self->codec, method, args, &error);
187  if (message == nullptr) {
188  if (task != nullptr) {
189  g_task_return_error(task, error);
190  }
191  return;
192  }
193 
195  self->messenger, self->name, message, cancellable,
196  callback != nullptr ? message_response_cb : nullptr,
197  g_steal_pointer(&task));
198 }
199 
200 G_MODULE_EXPORT FlMethodResponse* fl_method_channel_invoke_method_finish(
201  FlMethodChannel* self,
202  GAsyncResult* result,
203  GError** error) {
204  g_return_val_if_fail(FL_IS_METHOD_CHANNEL(self), nullptr);
205  g_return_val_if_fail(g_task_is_valid(result, self), nullptr);
206 
207  g_autoptr(GTask) task = G_TASK(result);
208  GAsyncResult* r = G_ASYNC_RESULT(g_task_propagate_pointer(task, nullptr));
209 
210  g_autoptr(GBytes) response =
211  fl_binary_messenger_send_on_channel_finish(self->messenger, r, error);
212  if (response == nullptr) {
213  return nullptr;
214  }
215 
216  return fl_method_codec_decode_response(self->codec, response, error);
217 }
218 
220  FlMethodChannel* self,
221  FlBinaryMessengerResponseHandle* response_handle,
222  FlMethodResponse* response,
223  GError** error) {
224  g_return_val_if_fail(FL_IS_METHOD_CHANNEL(self), FALSE);
225  g_return_val_if_fail(FL_IS_BINARY_MESSENGER_RESPONSE_HANDLE(response_handle),
226  FALSE);
227  g_return_val_if_fail(FL_IS_METHOD_SUCCESS_RESPONSE(response) ||
228  FL_IS_METHOD_ERROR_RESPONSE(response) ||
229  FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response),
230  FALSE);
231 
232  g_autoptr(GBytes) message = nullptr;
233  if (FL_IS_METHOD_SUCCESS_RESPONSE(response)) {
234  FlMethodSuccessResponse* r = FL_METHOD_SUCCESS_RESPONSE(response);
236  self->codec, fl_method_success_response_get_result(r), error);
237  if (message == nullptr) {
238  return FALSE;
239  }
240  } else if (FL_IS_METHOD_ERROR_RESPONSE(response)) {
241  FlMethodErrorResponse* r = FL_METHOD_ERROR_RESPONSE(response);
243  self->codec, fl_method_error_response_get_code(r),
246  if (message == nullptr) {
247  return FALSE;
248  }
249  } else if (FL_IS_METHOD_NOT_IMPLEMENTED_RESPONSE(response)) {
250  message = nullptr;
251  } else {
252  g_assert_not_reached();
253  }
254 
255  return fl_binary_messenger_send_response(self->messenger, response_handle,
256  message, error);
257 }
gboolean fl_method_channel_respond(FlMethodChannel *self, FlBinaryMessengerResponseHandle *response_handle, FlMethodResponse *response, GError **error)
G_BEGIN_DECLS FlValue * args
GDestroyNotify method_call_handler_destroy_notify
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)
static void message_response_cb(GObject *object, GAsyncResult *result, gpointer user_data)
GBytes * fl_method_codec_encode_method_call(FlMethodCodec *self, const gchar *name, FlValue *args, GError **error)
G_BEGIN_DECLS FlMethodCall * method_call
G_MODULE_EXPORT FlMethodResponse * fl_method_channel_invoke_method_finish(FlMethodChannel *self, GAsyncResult *result, GError **error)
const uint8_t uint32_t uint32_t GError ** error
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:40
static void message_cb(FlBinaryMessenger *messenger, const gchar *channel, GBytes *message, FlBinaryMessengerResponseHandle *response_handle, gpointer user_data)
G_MODULE_EXPORT GBytes * fl_binary_messenger_send_on_channel_finish(FlBinaryMessenger *self, GAsyncResult *result, GError **error)
void * user_data
G_MODULE_EXPORT FlValue * fl_method_success_response_get_result(FlMethodSuccessResponse *self)
GAsyncResult * result
FlMethodCall * fl_method_call_new(const gchar *name, FlValue *args, FlMethodChannel *channel, FlBinaryMessengerResponseHandle *response_handle)
static void fl_method_channel_class_init(FlMethodChannelClass *klass)
G_MODULE_EXPORT const gchar * fl_method_error_response_get_message(FlMethodErrorResponse *self)
FlKeyEvent FlKeyResponderAsyncCallback callback
G_MODULE_EXPORT GType fl_method_channel_get_type()
G_MODULE_EXPORT gboolean fl_binary_messenger_send_response(FlBinaryMessenger *self, FlBinaryMessengerResponseHandle *response_handle, GBytes *response, GError **error)
FlMethodCodec * codec
static void fl_method_channel_init(FlMethodChannel *self)
G_MODULE_EXPORT void fl_binary_messenger_send_on_channel(FlBinaryMessenger *self, const gchar *channel, GBytes *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
FlBinaryMessenger * messenger
FlMethodChannelMethodCallHandler method_call_handler
G_MODULE_EXPORT void fl_method_channel_set_method_call_handler(FlMethodChannel *self, FlMethodChannelMethodCallHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
G_MODULE_EXPORT FlMethodChannel * fl_method_channel_new(FlBinaryMessenger *messenger, const gchar *name, FlMethodCodec *codec)
static void fl_method_channel_dispose(GObject *object)
gpointer method_call_handler_data
FlMethodResponse * fl_method_codec_decode_response(FlMethodCodec *self, GBytes *message, GError **error)
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 channel_closed_cb(gpointer user_data)
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 const gchar * fl_method_error_response_get_code(FlMethodErrorResponse *self)
GBytes * fl_method_codec_encode_error_envelope(FlMethodCodec *self, const gchar *code, const gchar *message, FlValue *details, GError **error)
return FALSE
GBytes * fl_method_codec_encode_success_envelope(FlMethodCodec *self, FlValue *result, GError **error)
gboolean fl_method_codec_decode_method_call(FlMethodCodec *self, GBytes *message, gchar **name, FlValue **args, GError **error)
G_MODULE_EXPORT FlValue * fl_method_error_response_get_details(FlMethodErrorResponse *self)