Bug 1382251: Part 6 - Start/stop new top-level brokering actors on their own threads r=jld
☠☠ backed out by 398fb8533bcb ☠ ☠
authorDavid Parks <dparks@mozilla.com>
Mon, 06 Nov 2017 10:29:15 -0800
changeset 399853 95701ac611fa0e4a18d76d55bb39c0a79e6b0dde
parent 399852 37cad137215fa5ef9febbeb9401ff35269a769ab
child 399854 09cb062d95ee6685bbbd495daebbbd312dc20e85
push id33279
push useraciure@mozilla.com
push dateThu, 18 Jan 2018 21:53:37 +0000
treeherdermozilla-central@cffb3cd9dbb1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjld
bugs1382251
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1382251: Part 6 - Start/stop new top-level brokering actors on their own threads r=jld The FunctionBroker actors allow the NPAPI process (child) to run methods on the main process (parent). Both the parent and the child run dedicated threads for this task -- this is a top-level protocol.
dom/plugins/ipc/FunctionBrokerChild.cpp
dom/plugins/ipc/FunctionBrokerChild.h
dom/plugins/ipc/FunctionBrokerParent.cpp
dom/plugins/ipc/FunctionBrokerParent.h
dom/plugins/ipc/FunctionBrokerThread.h
dom/plugins/ipc/PFunctionBroker.ipdl
dom/plugins/ipc/PPluginModule.ipdl
dom/plugins/ipc/PluginModuleChild.cpp
dom/plugins/ipc/PluginModuleChild.h
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
ipc/ipdl/sync-messages.ini
toolkit/xre/nsAppRunner.cpp
xpcom/build/nsXULAppAPI.h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/FunctionBrokerChild.cpp
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FunctionBrokerChild.h"
+#include "FunctionBrokerThread.h"
+
+namespace mozilla {
+namespace plugins {
+
+FunctionBrokerChild* FunctionBrokerChild::sInstance = nullptr;
+
+bool
+FunctionBrokerChild::IsDispatchThread()
+{
+  return mThread->IsOnThread();
+}
+
+void
+FunctionBrokerChild::PostToDispatchThread(already_AddRefed<nsIRunnable>&& runnable)
+{
+  mThread->Dispatch(Move(runnable));
+}
+
+/* static */ bool
+FunctionBrokerChild::Initialize(Endpoint<PFunctionBrokerChild>&& aBrokerEndpoint)
+{
+  MOZ_RELEASE_ASSERT(XRE_IsPluginProcess(),
+                     "FunctionBrokerChild can only be used in plugin processes");
+
+  MOZ_ASSERT(!sInstance);
+  FunctionBrokerThread* thread = FunctionBrokerThread::Create();
+  if (!thread) {
+    return false;
+  }
+  sInstance = new FunctionBrokerChild(thread, Move(aBrokerEndpoint));
+  return true;
+}
+
+/* static */ FunctionBrokerChild*
+FunctionBrokerChild::GetInstance()
+{
+  MOZ_RELEASE_ASSERT(XRE_IsPluginProcess(),
+                     "FunctionBrokerChild can only be used in plugin processes");
+
+  MOZ_ASSERT(sInstance, "Must initialize FunctionBrokerChild before using it");
+  return sInstance;
+}
+
+FunctionBrokerChild::FunctionBrokerChild(FunctionBrokerThread* aThread,
+                                         Endpoint<PFunctionBrokerChild>&& aEndpoint) :
+    mThread(aThread)
+  , mShutdownDone(false)
+  , mMonitor("FunctionBrokerChild Lock")
+{
+  MOZ_ASSERT(aThread);
+  PostToDispatchThread(NewNonOwningRunnableMethod<Endpoint<PFunctionBrokerChild>&&>(
+                       "FunctionBrokerChild::Bind", this, &FunctionBrokerChild::Bind,
+                       Move(aEndpoint)));
+}
+
+void
+FunctionBrokerChild::Bind(Endpoint<PFunctionBrokerChild>&& aEndpoint)
+{
+  MOZ_RELEASE_ASSERT(mThread->IsOnThread());
+  DebugOnly<bool> ok = aEndpoint.Bind(this);
+  MOZ_ASSERT(ok);
+}
+
+void
+FunctionBrokerChild::ShutdownOnDispatchThread()
+{
+  MOZ_ASSERT(mThread->IsOnThread());
+
+  // Set mShutdownDone and notify waiting thread (if any) that we are done.
+  MonitorAutoLock lock(mMonitor);
+  mShutdownDone = true;
+  mMonitor.Notify();
+}
+
+void
+FunctionBrokerChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  MOZ_ASSERT(mThread->IsOnThread());
+
+  // Queue up a task on the PD thread.  When that task is executed then
+  // we know that anything queued before ActorDestroy has completed.
+  // At that point, we can set mShutdownDone and alert any waiting
+  // threads that it is safe to destroy us.
+  sInstance->PostToDispatchThread(NewNonOwningRunnableMethod(
+                                  "FunctionBrokerChild::ShutdownOnDispatchThread", sInstance,
+                                  &FunctionBrokerChild::ShutdownOnDispatchThread));
+}
+
+void
+FunctionBrokerChild::Destroy()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!sInstance) {
+    return;
+  }
+
+  // mShutdownDone will tell us when ActorDestroy has been run and any tasks
+  // on the FunctionBrokerThread have completed.  At that point, we can
+  // safely delete the actor.
+  {
+    MonitorAutoLock lock(sInstance->mMonitor);
+    while (!sInstance->mShutdownDone) {
+      // Release lock and wait.  Regain lock when we are notified that
+      // we have ShutdownOnDispatchThread.
+      sInstance->mMonitor.Wait();
+    }
+  }
+
+  delete sInstance;
+  sInstance = nullptr;
+}
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/FunctionBrokerChild.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_plugins_functionbrokerchild_h
+#define mozilla_plugins_functionbrokerchild_h
+
+#include "mozilla/plugins/PFunctionBrokerChild.h"
+
+namespace mozilla {
+namespace plugins {
+
+class FunctionBrokerThread;
+
+/**
+ * Dispatches brokered methods to the Parent process to allow functionality
+ * that is otherwise blocked by the sandbox.
+ */
+class FunctionBrokerChild : public PFunctionBrokerChild
+{
+public:
+  static bool Initialize(Endpoint<PFunctionBrokerChild>&& aBrokerEndpoint);
+  static FunctionBrokerChild* GetInstance();
+  static void Destroy();
+
+  bool IsDispatchThread();
+  void PostToDispatchThread(already_AddRefed<nsIRunnable>&& runnable);
+
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+
+private:
+  explicit FunctionBrokerChild(FunctionBrokerThread* aThread,
+                               Endpoint<PFunctionBrokerChild>&& aEndpoint);
+  void ShutdownOnDispatchThread();
+  void Bind(Endpoint<PFunctionBrokerChild>&& aEndpoint);
+
+  nsAutoPtr<FunctionBrokerThread> mThread;
+
+  // True if tasks on the FunctionBrokerThread have completed
+  bool mShutdownDone;
+  // This monitor guards mShutdownDone.
+  Monitor mMonitor;
+
+  static FunctionBrokerChild* sInstance;
+};
+
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif // mozilla_plugins_functionbrokerchild_h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/FunctionBrokerParent.cpp
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FunctionBrokerParent.h"
+#include "FunctionBroker.h"
+#include "FunctionBrokerThread.h"
+
+namespace mozilla {
+namespace plugins {
+
+/* static */ FunctionBrokerParent*
+FunctionBrokerParent::Create(Endpoint<PFunctionBrokerParent>&& aParentEnd)
+{
+  FunctionBrokerThread* thread = FunctionBrokerThread::Create();
+  if (!thread) {
+    return nullptr;
+  }
+  return new FunctionBrokerParent(thread, Move(aParentEnd));
+}
+
+FunctionBrokerParent::FunctionBrokerParent(FunctionBrokerThread* aThread,
+                                           Endpoint<PFunctionBrokerParent>&& aParentEnd) :
+    mThread(aThread)
+  , mMonitor("FunctionBrokerParent Lock")
+  , mShutdownDone(false)
+{
+  MOZ_ASSERT(mThread);
+  mThread->Dispatch(NewNonOwningRunnableMethod<Endpoint<PFunctionBrokerParent>&&>(
+          "FunctionBrokerParent::Bind", this, &FunctionBrokerParent::Bind, Move(aParentEnd)));
+}
+
+void
+FunctionBrokerParent::Bind(Endpoint<PFunctionBrokerParent>&& aEnd)
+{
+  MOZ_RELEASE_ASSERT(mThread->IsOnThread());
+  DebugOnly<bool> ok = aEnd.Bind(this);
+  MOZ_ASSERT(ok);
+}
+
+void
+FunctionBrokerParent::ShutdownOnBrokerThread()
+{
+  MOZ_ASSERT(mThread->IsOnThread());
+  Close();
+
+  // Notify waiting thread that we are done.
+  MonitorAutoLock lock(mMonitor);
+  mShutdownDone = true;
+  mMonitor.Notify();
+}
+
+void
+FunctionBrokerParent::Destroy(FunctionBrokerParent* aInst)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aInst);
+
+  {
+    // Hold the lock while we destroy the actor on the broker thread.
+    MonitorAutoLock lock(aInst->mMonitor);
+    aInst->mThread->Dispatch(NewNonOwningRunnableMethod(
+      "FunctionBrokerParent::ShutdownOnBrokerThread", aInst,
+      &FunctionBrokerParent::ShutdownOnBrokerThread));
+
+    // Wait for broker thread to complete destruction.
+    while (!aInst->mShutdownDone) {
+      aInst->mMonitor.Wait();
+    }
+  }
+
+  delete aInst;
+}
+
+void
+FunctionBrokerParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  MOZ_RELEASE_ASSERT(mThread->IsOnThread());
+}
+
+} // namespace plugins
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/FunctionBrokerParent.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_plugins_functionbrokerparent_h
+#define mozilla_plugins_functionbrokerparent_h
+
+#include "mozilla/plugins/PFunctionBrokerParent.h"
+
+namespace mozilla {
+namespace plugins {
+
+class FunctionBrokerThread;
+
+/**
+ * Top-level actor run on the process to which we broker calls from sandboxed
+ * plugin processes.
+ */
+class FunctionBrokerParent : public PFunctionBrokerParent
+{
+public:
+  static FunctionBrokerParent* Create(Endpoint<PFunctionBrokerParent>&& aParentEnd);
+  static void Destroy(FunctionBrokerParent* aInst);
+
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+
+private:
+  explicit FunctionBrokerParent(FunctionBrokerThread* aThread,
+                                Endpoint<PFunctionBrokerParent>&& aParentEnd);
+  void ShutdownOnBrokerThread();
+  void Bind(Endpoint<PFunctionBrokerParent>&& aEnd);
+
+  nsAutoPtr<FunctionBrokerThread> mThread;
+  Monitor mMonitor;
+  bool mShutdownDone;
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif // mozilla_plugins_functionbrokerparent_hk
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/FunctionBrokerThread.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: sw=4 ts=4 et :
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_plugins_functionbrokerthread_h
+#define mozilla_plugins_functionbrokerthread_h
+
+#include "nsThreadManager.h"
+
+namespace mozilla {
+namespace plugins {
+
+class FunctionBrokerThread
+{
+public:
+  void Dispatch(already_AddRefed<nsIRunnable>&& aRunnable)
+  {
+    mThread->Dispatch(Move(aRunnable), nsIEventTarget::NS_DISPATCH_NORMAL);
+  }
+
+  bool IsOnThread()
+  {
+    bool on;
+    return NS_SUCCEEDED(mThread->IsOnCurrentThread(&on)) && on;
+  }
+
+  static FunctionBrokerThread* Create()
+  {
+    MOZ_RELEASE_ASSERT(NS_IsMainThread());
+    nsCOMPtr<nsIThread> thread;
+    if (NS_FAILED(NS_NewNamedThread("Function Broker", getter_AddRefs(thread)))) {
+      return nullptr;
+    }
+    return new FunctionBrokerThread(thread);
+  }
+
+  ~FunctionBrokerThread()
+  {
+    MOZ_RELEASE_ASSERT(NS_IsMainThread());
+    mThread->Shutdown();
+  }
+
+private:
+  explicit FunctionBrokerThread(nsIThread* aThread) : mThread(aThread)
+  {
+    MOZ_ASSERT(mThread);
+  }
+
+  nsCOMPtr<nsIThread> mThread;
+};
+
+} // namespace plugins
+} // namespace mozilla
+
+#endif // mozilla_plugins_functionbrokerthread_h
new file mode 100644
--- /dev/null
+++ b/dom/plugins/ipc/PFunctionBroker.ipdl
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+using mozilla::plugins::FunctionHookId from "mozilla/plugins/FunctionBrokerIPCUtils.h";
+using IPC::IpdlTuple from "mozilla/plugins/IpdlTuple.h";
+
+namespace mozilla {
+namespace plugins {
+
+/**
+ * Top-level actor that brokers functions for the client process.
+ */
+sync protocol PFunctionBroker
+{
+parent:
+  sync BrokerFunction(FunctionHookId aFunctionId, IpdlTuple aFunctionParams)
+    returns (IpdlTuple aFunctionRet);
+};
+
+} // namespace plugins
+} // namespace mozilla
--- a/dom/plugins/ipc/PPluginModule.ipdl
+++ b/dom/plugins/ipc/PPluginModule.ipdl
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PPluginInstance;
 include protocol PPluginScriptableObject;
 include protocol PContent;
 include protocol PProfiler;
+include protocol PFunctionBroker;
 
 using NPError from "npapi.h";
 using NPNVariable from "npapi.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using class mac_plugin_interposing::NSCursorInfo from "mozilla/plugins/PluginMessageUtils.h";
 using struct nsID from "nsID.h";
 using struct mozilla::plugins::NPAudioDeviceChangeDetailsIPC from "mozilla/plugins/PluginMessageUtils.h";
 using mozilla::plugins::GetFileNameFunc from "mozilla/plugins/PluginMessageUtils.h";
@@ -93,16 +94,18 @@ child:
     returns (NativeThreadId tid);
 
   async SettingChanged(PluginSettings settings);
 
   async NPP_SetValue_NPNVaudioDeviceChangeDetails(NPAudioDeviceChangeDetailsIPC changeDetails);
 
   async InitPluginModuleChild(Endpoint<PPluginModuleChild> endpoint);
 
+  async InitPluginFunctionBroker(Endpoint<PFunctionBrokerChild> endpoint);
+
 parent:
   /**
    * This message is only used on X11 platforms.
    *
    * Send a dup of the plugin process's X socket to the parent
    * process.  In theory, this scheme keeps the plugin's X resources
    * around until after both the plugin process shuts down *and* the
    * parent process closes the dup fd.  This is used to prevent the
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -32,16 +32,18 @@
 #include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/plugins/PluginInstanceChild.h"
 #include "mozilla/plugins/StreamNotifyChild.h"
 #include "mozilla/plugins/BrowserStreamChild.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/Unused.h"
 
 #include "nsNPAPIPlugin.h"
+#include "FunctionHook.h"
+#include "FunctionBrokerChild.h"
 
 #ifdef XP_WIN
 #include "nsWindowsDllInterceptor.h"
 #include "mozilla/widget/AudioSession.h"
 #include <knownfolders.h>
 #include <shlobj.h>
 #endif
 
@@ -739,16 +741,31 @@ mozilla::ipc::IPCResult
 PluginModuleChild::RecvInitPluginModuleChild(Endpoint<PPluginModuleChild>&& aEndpoint)
 {
     if (!CreateForContentProcess(Move(aEndpoint))) {
         return IPC_FAIL(this, "CreateForContentProcess failed");
     }
     return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+PluginModuleChild::RecvInitPluginFunctionBroker(Endpoint<PFunctionBrokerChild>&& aEndpoint)
+{
+#if defined(XP_WIN)
+    MOZ_ASSERT(mIsChrome);
+    if (!FunctionBrokerChild::Initialize(Move(aEndpoint))) {
+      return IPC_FAIL(this,
+                      "InitPluginFunctionBroker failed to initialize broker child.");
+    }
+    return IPC_OK();
+#else
+    return IPC_FAIL(this, "InitPluginFunctionBroker not supported on this platform.");
+#endif
+}
+
 
 mozilla::ipc::IPCResult
 PluginModuleChild::AnswerInitCrashReporter(Shmem&& aShmem, mozilla::dom::NativeThreadId* aOutId)
 {
     CrashReporterClient::InitSingletonWithShmem(aShmem);
     *aOutId = CrashReporter::CurrentThreadId();
 
     return IPC_OK();
@@ -782,16 +799,21 @@ PluginModuleChild::ActorDestroy(ActorDes
         ProcessChild::QuickExit();
     }
 
     if (!mHasShutdown) {
         MOZ_ASSERT(gChromeInstance == this);
         NP_Shutdown();
     }
 
+#if defined(XP_WIN)
+    FunctionBrokerChild::Destroy();
+    FunctionHook::ClearDllInterceptorCache();
+#endif
+
     // doesn't matter why we're being destroyed; it's up to us to
     // initiate (clean) shutdown
     CrashReporterClient::DestroySingleton();
 
     XRE_ShutdownChildProcess();
 }
 
 void
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -73,16 +73,19 @@ protected:
     virtual mozilla::ipc::IPCResult AnswerNP_GetEntryPoints(NPError* rv) override;
     virtual mozilla::ipc::IPCResult AnswerNP_Initialize(const PluginSettings& aSettings, NPError* rv) override;
     virtual mozilla::ipc::IPCResult AnswerSyncNPP_New(PPluginInstanceChild* aActor, NPError* rv)
                                    override;
 
     virtual mozilla::ipc::IPCResult
     RecvInitPluginModuleChild(Endpoint<PPluginModuleChild>&& endpoint) override;
 
+    virtual mozilla::ipc::IPCResult
+    RecvInitPluginFunctionBroker(Endpoint<PFunctionBrokerChild>&& endpoint) override;
+
     virtual PPluginInstanceChild*
     AllocPPluginInstanceChild(const nsCString& aMimeType,
                               const InfallibleTArray<nsCString>& aNames,
                               const InfallibleTArray<nsCString>& aValues)
                               override;
 
     virtual bool
     DeallocPPluginInstanceChild(PPluginInstanceChild* aActor) override;
@@ -228,20 +231,16 @@ private:
       if (mQuirks == QUIRKS_NOT_INITIALIZED)
         mQuirks = 0;
       mQuirks |= quirk;
     }
     void InitQuirksModes(const nsCString& aMimeType);
     bool InitGraphics();
     void DeinitGraphics();
 
-#if defined(OS_WIN)
-    void HookProtectedMode();
-#endif
-
 #if defined(MOZ_WIDGET_GTK)
     static gboolean DetectNestedEventLoop(gpointer data);
     static gboolean ProcessBrowserEvents(gpointer data);
 
     virtual void EnteredCxxStack() override;
     virtual void ExitedCxxStack() override;
 #endif
 
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -38,16 +38,17 @@
 #include "nsPluginTags.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/layers/TextureClientRecycleAllocator.h"
 
 #ifdef XP_WIN
 #include "mozilla/plugins/PluginSurfaceParent.h"
 #include "mozilla/widget/AudioSession.h"
 #include "PluginHangUIParent.h"
+#include "FunctionBrokerParent.h"
 #include "PluginUtilsWin.h"
 #endif
 
 #ifdef MOZ_WIDGET_GTK
 #include <glib.h>
 #elif XP_MACOSX
 #include "PluginInterposeOSX.h"
 #include "PluginUtilsOSX.h"
@@ -481,16 +482,33 @@ PluginModuleChromeParent::LoadModule(con
     uint32_t blocklistState;
     nsresult rv = aPluginTag->GetBlocklistState(&blocklistState);
     parent->mIsBlocklisted = NS_FAILED(rv) || blocklistState != 0;
     int32_t launchTimeoutSecs = Preferences::GetInt(kLaunchTimeoutPref, 0);
     if (!parent->mSubprocess->WaitUntilConnected(launchTimeoutSecs * 1000)) {
         parent->mShutdown = true;
         return nullptr;
     }
+
+#if defined(XP_WIN)
+    Endpoint<PFunctionBrokerParent> brokerParentEnd;
+    Endpoint<PFunctionBrokerChild> brokerChildEnd;
+    rv = PFunctionBroker::CreateEndpoints(base::GetCurrentProcId(), parent->OtherPid(),
+                                        &brokerParentEnd, &brokerChildEnd);
+    if (NS_FAILED(rv)) {
+        parent->mShutdown = true;
+        return nullptr;
+    }
+
+    parent->mBrokerParent =
+      FunctionBrokerParent::Create(Move(brokerParentEnd));
+    if (parent->mBrokerParent) {
+      parent->SendInitPluginFunctionBroker(Move(brokerChildEnd));
+    }
+#endif
     return parent.forget();
 }
 
 void
 PluginModuleChromeParent::OnProcessLaunched(const bool aSucceeded)
 {
     if (!aSucceeded) {
         mShutdown = true;
@@ -617,16 +635,17 @@ PluginModuleChromeParent::PluginModuleCh
     , mPluginId(aPluginId)
     , mChromeTaskFactory(this)
     , mHangAnnotationFlags(0)
 #ifdef XP_WIN
     , mPluginCpuUsageOnHang()
     , mHangUIParent(nullptr)
     , mHangUIEnabled(true)
     , mIsTimerReset(true)
+    , mBrokerParent(nullptr)
 #endif
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     , mFlashProcess1(0)
     , mFlashProcess2(0)
     , mFinishInitTask(nullptr)
 #endif
 {
     NS_ASSERTION(mSubprocess, "Out of memory!");
@@ -1591,16 +1610,23 @@ PluginModuleChromeParent::ActorDestroy(A
         ProcessFirstMinidump();
         Telemetry::Accumulate(Telemetry::SUBPROCESS_ABNORMAL_ABORT,
                               NS_LITERAL_CSTRING("plugin"), 1);
     }
 
     // We can't broadcast settings changes anymore.
     UnregisterSettingsCallbacks();
 
+#if defined(XP_WIN)
+    if (mBrokerParent) {
+        FunctionBrokerParent::Destroy(mBrokerParent);
+        mBrokerParent = nullptr;
+    }
+#endif
+
     PluginModuleParent::ActorDestroy(why);
 }
 
 void
 PluginModuleParent::NotifyFlashHang()
 {
     nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
     if (obs) {
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -43,16 +43,17 @@ class TextureClientRecycleAllocator;
 namespace plugins {
 //-----------------------------------------------------------------------------
 
 class BrowserStreamParent;
 class PluginInstanceParent;
 
 #ifdef XP_WIN
 class PluginHangUIParent;
+class FunctionBrokerParent;
 #endif
 #ifdef MOZ_CRASHREPORTER_INJECTOR
 class FinishInjectorInitTask;
 #endif
 
 /**
  * PluginModuleParent
  *
@@ -583,16 +584,18 @@ private:
     bool
     LaunchHangUI();
 
     /**
      * Finishes the Plugin Hang UI and cancels if it is being shown to the user.
      */
     void
     FinishHangUI();
+
+    FunctionBrokerParent* mBrokerParent;
 #endif
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     friend class mozilla::plugins::FinishInjectorInitTask;
 
     void InitializeInjector();
     void DoInjection(const nsAutoHandle& aSnapshot);
     static DWORD WINAPI GetToolhelpSnapshot(LPVOID aContext);
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -654,16 +654,18 @@ description =
 
 # Plugins
 [PPluginWidget::Create]
 description =
 [PPluginWidget::GetNativePluginPort]
 description =
 [PPluginWidget::SetNativeChildWindow]
 description =
+[PFunctionBroker::BrokerFunction]
+description =
 [PPluginInstance::__delete__]
 description =
 [PPluginInstance::CreateChildPluginWindow]
 description =
 [PPluginInstance::NPP_SetWindow]
 description =
 [PPluginInstance::NPP_GetValue_NPPVpluginWantsAllNetworkStreams]
 description =
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -5050,16 +5050,22 @@ XRE_IsE10sParentProcess()
 
 bool
 XRE_IsContentProcess()
 {
   return XRE_GetProcessType() == GeckoProcessType_Content;
 }
 
 bool
+XRE_IsPluginProcess()
+{
+  return XRE_GetProcessType() == GeckoProcessType_Plugin;
+}
+
+bool
 XRE_UseNativeEventProcessing()
 {
   if (XRE_IsContentProcess()) {
     static bool sInited = false;
     static bool sUseNativeEventProcessing = false;
     if (!sInited) {
       Preferences::AddBoolVarCache(&sUseNativeEventProcessing,
                                    "dom.ipc.useNativeEventProcessing.content");
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -442,16 +442,19 @@ XRE_API(bool,
         XRE_IsParentProcess, ())
 
 XRE_API(bool,
         XRE_IsContentProcess, ())
 
 XRE_API(bool,
         XRE_IsGPUProcess, ())
 
+XRE_API(bool,
+        XRE_IsPluginProcess, ())
+
 /**
  * Returns true if the appshell should run its own native event loop. Returns
  * false if we should rely solely on the Gecko event loop.
  */
 XRE_API(bool,
         XRE_UseNativeEventProcessing, ())
 
 typedef void (*MainFunction)(void* aData);