Add FlPluginRegistry and FlPluginRegistrar (#18453)

* Add FlPluginRegistry and FlPluginRegistrar
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
index 4daa919..be25344 100755
--- a/ci/licenses_golden/licenses_flutter
+++ b/ci/licenses_golden/licenses_flutter
@@ -1215,6 +1215,9 @@
 FILE: ../../../flutter/shell/platform/linux/fl_method_codec_test.cc
 FILE: ../../../flutter/shell/platform/linux/fl_method_response.cc
 FILE: ../../../flutter/shell/platform/linux/fl_method_response_test.cc
+FILE: ../../../flutter/shell/platform/linux/fl_plugin_registrar.cc
+FILE: ../../../flutter/shell/platform/linux/fl_plugin_registrar_private.h
+FILE: ../../../flutter/shell/platform/linux/fl_plugin_registry.cc
 FILE: ../../../flutter/shell/platform/linux/fl_renderer.cc
 FILE: ../../../flutter/shell/platform/linux/fl_renderer.h
 FILE: ../../../flutter/shell/platform/linux/fl_renderer_x11.cc
@@ -1241,6 +1244,8 @@
 FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h
 FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h
 FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_method_response.h
+FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registrar.h
+FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h
 FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h
 FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h
 FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_string_codec.h
diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn
index 4782885..d425088 100644
--- a/shell/platform/linux/BUILD.gn
+++ b/shell/platform/linux/BUILD.gn
@@ -56,6 +56,8 @@
   "public/flutter_linux/fl_method_channel.h",
   "public/flutter_linux/fl_method_codec.h",
   "public/flutter_linux/fl_method_response.h",
+  "public/flutter_linux/fl_plugin_registrar.h",
+  "public/flutter_linux/fl_plugin_registry.h",
   "public/flutter_linux/fl_standard_message_codec.h",
   "public/flutter_linux/fl_standard_method_codec.h",
   "public/flutter_linux/fl_string_codec.h",
@@ -85,6 +87,8 @@
     "fl_method_channel.cc",
     "fl_method_codec.cc",
     "fl_method_response.cc",
+    "fl_plugin_registrar.cc",
+    "fl_plugin_registry.cc",
     "fl_renderer.cc",
     "fl_renderer_x11.cc",
     "fl_standard_message_codec.cc",
diff --git a/shell/platform/linux/fl_plugin_registrar.cc b/shell/platform/linux/fl_plugin_registrar.cc
new file mode 100644
index 0000000..9b01bed
--- /dev/null
+++ b/shell/platform/linux/fl_plugin_registrar.cc
@@ -0,0 +1,72 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registrar.h"
+#include "flutter/shell/platform/linux/fl_plugin_registrar_private.h"
+
+#include <gmodule.h>
+
+struct _FlPluginRegistrar {
+  GObject parent_instance;
+
+  // View that plugin is controlling.
+  FlView* view;
+
+  // Messenger to communicate on.
+  FlBinaryMessenger* messenger;
+};
+
+G_DEFINE_TYPE(FlPluginRegistrar, fl_plugin_registrar, G_TYPE_OBJECT)
+
+static void view_weak_notify_cb(gpointer user_data, GObject* object) {
+  FlPluginRegistrar* self = FL_PLUGIN_REGISTRAR(user_data);
+  self->view = nullptr;
+}
+
+static void fl_plugin_registrar_dispose(GObject* object) {
+  FlPluginRegistrar* self = FL_PLUGIN_REGISTRAR(object);
+
+  if (self->view != nullptr) {
+    g_object_weak_unref(G_OBJECT(self->view), view_weak_notify_cb, self);
+    self->view = nullptr;
+  }
+
+  g_clear_object(&self->messenger);
+
+  G_OBJECT_CLASS(fl_plugin_registrar_parent_class)->dispose(object);
+}
+
+static void fl_plugin_registrar_class_init(FlPluginRegistrarClass* klass) {
+  G_OBJECT_CLASS(klass)->dispose = fl_plugin_registrar_dispose;
+}
+
+static void fl_plugin_registrar_init(FlPluginRegistrar* self) {}
+
+FlPluginRegistrar* fl_plugin_registrar_new(FlView* view,
+                                           FlBinaryMessenger* messenger) {
+  g_return_val_if_fail(FL_IS_VIEW(view), nullptr);
+  g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr);
+
+  FlPluginRegistrar* self = FL_PLUGIN_REGISTRAR(
+      g_object_new(fl_plugin_registrar_get_type(), nullptr));
+
+  self->view = view;
+  g_object_weak_ref(G_OBJECT(view), view_weak_notify_cb, self);
+  self->messenger = FL_BINARY_MESSENGER(g_object_ref(messenger));
+
+  return self;
+}
+
+G_MODULE_EXPORT FlBinaryMessenger* fl_plugin_registrar_get_messenger(
+    FlPluginRegistrar* self) {
+  g_return_val_if_fail(FL_IS_PLUGIN_REGISTRAR(self), nullptr);
+
+  return self->messenger;
+}
+
+G_MODULE_EXPORT FlView* fl_plugin_registrar_get_view(FlPluginRegistrar* self) {
+  g_return_val_if_fail(FL_IS_PLUGIN_REGISTRAR(self), nullptr);
+
+  return self->view;
+}
diff --git a/shell/platform/linux/fl_plugin_registrar_private.h b/shell/platform/linux/fl_plugin_registrar_private.h
new file mode 100644
index 0000000..3a3b753
--- /dev/null
+++ b/shell/platform/linux/fl_plugin_registrar_private.h
@@ -0,0 +1,27 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_PLUGIN_REGISTRAR_PRIVATE_H_
+#define FLUTTER_SHELL_PLATFORM_LINUX_FL_PLUGIN_REGISTRAR_PRIVATE_H_
+
+#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h"
+#include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registrar.h"
+
+G_BEGIN_DECLS
+
+/**
+ * fl_plugin_registrar_new:
+ * @view: the #FlView that is being plugged into.
+ * @messenger: the #FlBinaryMessenger to communicate with.
+ *
+ * Creates a new #FlPluginRegistrar.
+ *
+ * Returns: a new #FlPluginRegistrar.
+ */
+FlPluginRegistrar* fl_plugin_registrar_new(FlView* view,
+                                           FlBinaryMessenger* messenger);
+
+G_END_DECLS
+
+#endif  // FLUTTER_SHELL_PLATFORM_LINUX_FL_PLUGIN_REGISTRAR_PRIVATE_H_
diff --git a/shell/platform/linux/fl_plugin_registry.cc b/shell/platform/linux/fl_plugin_registry.cc
new file mode 100644
index 0000000..f247d3b
--- /dev/null
+++ b/shell/platform/linux/fl_plugin_registry.cc
@@ -0,0 +1,24 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h"
+
+#include <gmodule.h>
+
+// Added here to stop the compiler from optimising this function away.
+G_MODULE_EXPORT GType fl_plugin_registry_get_type();
+
+G_DEFINE_INTERFACE(FlPluginRegistry, fl_plugin_registry, G_TYPE_OBJECT)
+
+void fl_plugin_registry_default_init(FlPluginRegistryInterface* self) {}
+
+G_MODULE_EXPORT FlPluginRegistrar* fl_plugin_registry_get_registrar_for_plugin(
+    FlPluginRegistry* self,
+    const gchar* name) {
+  g_return_val_if_fail(FL_IS_PLUGIN_REGISTRY(self), nullptr);
+  g_return_val_if_fail(name != nullptr, nullptr);
+
+  return FL_PLUGIN_REGISTRY_GET_IFACE(self)->get_registrar_for_plugin(self,
+                                                                      name);
+}
diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc
index 3b1c2c7..b3d3bb6 100644
--- a/shell/platform/linux/fl_view.cc
+++ b/shell/platform/linux/fl_view.cc
@@ -6,8 +6,10 @@
 
 #include "flutter/shell/platform/linux/fl_engine_private.h"
 #include "flutter/shell/platform/linux/fl_key_event_plugin.h"
+#include "flutter/shell/platform/linux/fl_plugin_registrar_private.h"
 #include "flutter/shell/platform/linux/fl_renderer_x11.h"
 #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
+#include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h"
 
 #include <gdk/gdkx.h>
 
@@ -34,7 +36,15 @@
 
 enum { PROP_FLUTTER_PROJECT = 1, PROP_LAST };
 
-G_DEFINE_TYPE(FlView, fl_view, GTK_TYPE_WIDGET)
+static void fl_view_plugin_registry_iface_init(
+    FlPluginRegistryInterface* iface);
+
+G_DEFINE_TYPE_WITH_CODE(
+    FlView,
+    fl_view,
+    GTK_TYPE_WIDGET,
+    G_IMPLEMENT_INTERFACE(fl_plugin_registry_get_type(),
+                          fl_view_plugin_registry_iface_init))
 
 // Converts a GDK button event into a Flutter event and sends it to the engine.
 static gboolean fl_view_send_pointer_button_event(FlView* self,
@@ -80,6 +90,21 @@
   return TRUE;
 }
 
+// Implements FlPluginRegistry::get_registrar_for_plugin
+static FlPluginRegistrar* fl_view_get_registrar_for_plugin(
+    FlPluginRegistry* registry,
+    const gchar* name) {
+  FlView* self = FL_VIEW(registry);
+
+  return fl_plugin_registrar_new(self,
+                                 fl_engine_get_binary_messenger(self->engine));
+}
+
+static void fl_view_plugin_registry_iface_init(
+    FlPluginRegistryInterface* iface) {
+  iface->get_registrar_for_plugin = fl_view_get_registrar_for_plugin;
+}
+
 static void fl_view_constructed(GObject* object) {
   FlView* self = FL_VIEW(object);
 
diff --git a/shell/platform/linux/public/flutter_linux/fl_plugin_registrar.h b/shell/platform/linux/public/flutter_linux/fl_plugin_registrar.h
new file mode 100644
index 0000000..1d5dc14
--- /dev/null
+++ b/shell/platform/linux/public/flutter_linux/fl_plugin_registrar.h
@@ -0,0 +1,53 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_PLUGIN_REGISTRAR_H_
+#define FLUTTER_SHELL_PLATFORM_LINUX_FL_PLUGIN_REGISTRAR_H_
+
+#if !defined(__FLUTTER_LINUX_INSIDE__) && !defined(FLUTTER_LINUX_COMPILATION)
+#error "Only <flutter_linux/flutter_linux.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+#include "fl_binary_messenger.h"
+#include "fl_view.h"
+
+G_BEGIN_DECLS
+
+G_DECLARE_FINAL_TYPE(FlPluginRegistrar,
+                     fl_plugin_registrar,
+                     FL,
+                     PLUGIN_REGISTRAR,
+                     GObject)
+
+/**
+ * FlPluginRegistrar:
+ *
+ * #FlPluginRegistrar is used when registering new plugins.
+ */
+
+/**
+ * fl_plugin_registrar_get_messenger:
+ * @registrar: an #FlPluginRegistrar.
+ *
+ * Gets the messenger this plugin can communicate with.
+ *
+ * Returns: an #FlBinaryMessenger.
+ */
+FlBinaryMessenger* fl_plugin_registrar_get_messenger(
+    FlPluginRegistrar* registrar);
+
+/**
+ * fl_plugin_registrar_get_view:
+ * @registrar: an #FlPluginRegistrar.
+ *
+ * Get the view that Flutter is rendering with.
+ *
+ * Returns: (allow-none): an #FlView or %NULL if running in headless mode.
+ */
+FlView* fl_plugin_registrar_get_view(FlPluginRegistrar* registrar);
+
+G_END_DECLS
+
+#endif  // FLUTTER_SHELL_PLATFORM_LINUX_FL_PLUGIN_REGISTRAR_H_
diff --git a/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h b/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h
new file mode 100644
index 0000000..1e1cbb5
--- /dev/null
+++ b/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h
@@ -0,0 +1,60 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_PLUGIN_REGISTRY_H_
+#define FLUTTER_SHELL_PLATFORM_LINUX_FL_PLUGIN_REGISTRY_H_
+
+#if !defined(__FLUTTER_LINUX_INSIDE__) && !defined(FLUTTER_LINUX_COMPILATION)
+#error "Only <flutter_linux/flutter_linux.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+#include "fl_plugin_registrar.h"
+
+G_BEGIN_DECLS
+
+G_DECLARE_INTERFACE(FlPluginRegistry,
+                    fl_plugin_registry,
+                    FL,
+                    PLUGIN_REGISTRY,
+                    GObject)
+
+/**
+ * FlPluginRegistry:
+ *
+ * #FlPluginRegistry vends #FlPluginRegistrar objects for named plugins.
+ */
+
+struct _FlPluginRegistryInterface {
+  GTypeInterface g_iface;
+
+  /**
+   * FlPluginRegistry::get_registrar_for_plugin:
+   * @registry: an #FlPluginRegistry.
+   * @name: plugin name.
+   *
+   * Gets the plugin registrar for the the plugin with @name.
+   *
+   * Returns: (transfer full): an #FlPluginRegistrar.
+   */
+  FlPluginRegistrar* (*get_registrar_for_plugin)(FlPluginRegistry* registry,
+                                                 const gchar* name);
+};
+
+/**
+ * fl_plugin_registry_get_registrar_for_plugin:
+ * @registry: an #FlPluginRegistry.
+ * @name: plugin name.
+ *
+ * Gets the plugin registrar for the the plugin with @name.
+ *
+ * Returns: (transfer full): an #FlPluginRegistrar.
+ */
+FlPluginRegistrar* fl_plugin_registry_get_registrar_for_plugin(
+    FlPluginRegistry* registry,
+    const gchar* name);
+
+G_END_DECLS
+
+#endif  // FLUTTER_SHELL_PLATFORM_LINUX_FL_PLUGIN_REGISTRY_H_
diff --git a/shell/platform/linux/public/flutter_linux/flutter_linux.h b/shell/platform/linux/public/flutter_linux/flutter_linux.h
index 03f9dfe..aeaef59 100644
--- a/shell/platform/linux/public/flutter_linux/flutter_linux.h
+++ b/shell/platform/linux/public/flutter_linux/flutter_linux.h
@@ -19,6 +19,8 @@
 #include <flutter_linux/fl_method_channel.h>
 #include <flutter_linux/fl_method_codec.h>
 #include <flutter_linux/fl_method_response.h>
+#include <flutter_linux/fl_plugin_registrar.h>
+#include <flutter_linux/fl_plugin_registry.h>
 #include <flutter_linux/fl_standard_message_codec.h>
 #include <flutter_linux/fl_standard_method_codec.h>
 #include <flutter_linux/fl_string_codec.h>