Bug 1127378 - When tabs close notify PluginWidgetChild earlier in shutdown. Prevents PluginWidgetProxy messages sent to dead parent actors triggering content process aborts. r=akotz
authorJim Mathies <jmathies@mozilla.com>
Tue, 03 Feb 2015 13:58:32 -0600
changeset 227288 ee13449af6e78d886a07d641aae87f7e7ea24bf5
parent 227287 d3b41b0ead7d0ac39057baca4be9392878d28e4c
child 227289 ea2dd189792da9040bf9c36751bc0a6df948ebf1
child 228128 bca7d6e774869a378979e2f5f1d365495bf3769c
push id55079
push userjmathies@mozilla.com
push dateTue, 03 Feb 2015 23:07:47 +0000
treeherdermozilla-inbound@ee13449af6e7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersakotz
bugs1127378
milestone38.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 1127378 - When tabs close notify PluginWidgetChild earlier in shutdown. Prevents PluginWidgetProxy messages sent to dead parent actors triggering content process aborts. r=akotz
dom/ipc/PPluginWidget.ipdl
dom/plugins/ipc/PluginWidgetChild.cpp
dom/plugins/ipc/PluginWidgetChild.h
dom/plugins/ipc/PluginWidgetParent.cpp
dom/plugins/ipc/PluginWidgetParent.h
--- a/dom/ipc/PPluginWidget.ipdl
+++ b/dom/ipc/PPluginWidget.ipdl
@@ -42,22 +42,21 @@ parent:
    * window for plugins. On Linux, this returns an XID for a socket widget
    * embedded in the chrome side native window. On Windows this returns the
    * native HWND of the plugin widget.
    */
   sync GetNativePluginPort() returns (uintptr_t value);
 
 child:
   /**
-   * Sent from content when a plugin is unloaded via layout. We shut down
-   * some things in response to this so that we don't end up firing async
-   * msgs after the child is destroyed. We know that after this call
-   * the child actor may not be on the other side.
+   * Sent from chrome when the chrome side widget is getting torn down.
+   * @param aParentInitiated - indicates if the shutdown is associated
+   * with a tab closure vs. content reload.
    */
-  async ParentShutdown();
+  async ParentShutdown(bool aParentInitiated);
 
   /**
    * Requests a full update of the plugin window.
    */
   async UpdateWindow(uintptr_t aChildId);
 };
 
 }
--- a/dom/plugins/ipc/PluginWidgetChild.cpp
+++ b/dom/plugins/ipc/PluginWidgetChild.cpp
@@ -7,59 +7,75 @@
 #include "mozilla/DebugOnly.h"
 #include "nsDebug.h"
 
 #if defined(XP_WIN)
 #include "mozilla/plugins/PluginInstanceParent.h"
 using mozilla::plugins::PluginInstanceParent;
 #endif
 
+#define PWLOG(...)
+//#define PWLOG(...) printf_stderr(__VA_ARGS__)
+
 namespace mozilla {
 namespace plugins {
 
 PluginWidgetChild::PluginWidgetChild() :
   mWidget(nullptr)
 {
   MOZ_COUNT_CTOR(PluginWidgetChild);
 }
 
 PluginWidgetChild::~PluginWidgetChild()
 {
+  PWLOG("PluginWidgetChild::~PluginWidgetChild()\n");
   MOZ_COUNT_DTOR(PluginWidgetChild);
 }
 
 /*
  * Tear down scenarios
  * layout (plugin content unloading):
- *  - PluginWidgetProxy nsIWidget Destroy()
- *  - PluginWidgetProxy->PluginWidgetChild->SendDestroy()
- *  - PluginWidgetParent::RecvDestroy(), sends async Destroyed() to PluginWidgetChild
- *  - PluginWidgetChild::RecvDestroyed() calls Send__delete__()
+ *  - PluginWidgetProxy::Destroy(), calls PluginWidgetChild->SendDestroy(), (proxy disabled)
+ *  - PluginWidgetParent::RecvDestroy(), sends async ParentShutdown()
+ *  - PluginWidgetChild::RecvParentShutdown(), calls Send__delete__()
  *  - PluginWidgetParent::ActorDestroy() called in response to __delete__.
  * PBrowser teardown (tab closing):
- *  - PluginWidgetParent::ParentDestroy() called by TabParent::Destroy()
+ *  - TabParent::Destroy()
+ *  - PluginWidgetParent::ParentDestroy(), sends async ParentShutdown()
+ *  - PluginWidgetChild::RecvParentShutdown(), (proxy disabled)
  *  - PluginWidgetParent::ActorDestroy()
  *  - PluginWidgetParent::~PluginWidgetParent() in response to PBrowserParent::DeallocSubtree()
  *  - PluginWidgetChild::ActorDestroy() from PPluginWidgetChild::DestroySubtree
  *  - ~PluginWidgetChild() in response to PBrowserChild::DeallocSubtree()
  **/
 
 void
-PluginWidgetChild::ActorDestroy(ActorDestroyReason aWhy)
+PluginWidgetChild::ShutdownProxy()
 {
   if (mWidget) {
     mWidget->ChannelDestroyed();
   }
   mWidget = nullptr;
 }
 
+void
+PluginWidgetChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  PWLOG("PluginWidgetChild::ActorDestroy(%d)\n", aWhy);
+  ShutdownProxy(); // backup
+}
+
 bool
-PluginWidgetChild::RecvParentShutdown()
+PluginWidgetChild::RecvParentShutdown(const bool& aParentInitiated)
 {
-  Send__delete__(this);
+  PWLOG("PluginWidgetChild::RecvParentShutdown(%d)\n", aParentInitiated);
+  ShutdownProxy();
+  if (!aParentInitiated) {
+    Send__delete__(this);
+  }
   return true;
 }
 
 bool
 PluginWidgetChild::RecvUpdateWindow(const uintptr_t& aChildId)
 {
 #if defined(XP_WIN)
   NS_ASSERTION(aChildId, "Expected child hwnd value for remote plugin instance.");
--- a/dom/plugins/ipc/PluginWidgetChild.h
+++ b/dom/plugins/ipc/PluginWidgetChild.h
@@ -16,17 +16,19 @@ namespace plugins {
 class PluginWidgetChild : public PPluginWidgetChild
 {
 public:
   PluginWidgetChild();
   virtual ~PluginWidgetChild();
 
   virtual bool RecvUpdateWindow(const uintptr_t& aChildId) MOZ_OVERRIDE;
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
-  virtual bool RecvParentShutdown() MOZ_OVERRIDE;
+  virtual bool RecvParentShutdown(const bool& aParentInitiated) MOZ_OVERRIDE;
+
+  void ShutdownProxy();
 
   mozilla::widget::PluginWidgetProxy* mWidget;
 };
 
 } // namespace plugins
 } // namespace mozilla
 
 #endif // mozilla_plugins_PluginWidgetChild_h
--- a/dom/plugins/ipc/PluginWidgetParent.cpp
+++ b/dom/plugins/ipc/PluginWidgetParent.cpp
@@ -165,49 +165,53 @@ PluginWidgetParent::RecvCreate()
   mWidget->RegisterPluginWindowForRemoteUpdates();
 
   return true;
 }
 
 void
 PluginWidgetParent::ActorDestroy(ActorDestroyReason aWhy)
 {
+  PWLOG("PluginWidgetParent::ActorDestroy()\n");
+}
+
+void
+PluginWidgetParent::ShutdownCommon(bool aParentInitiated)
+{
+  if (mActorDestroyed || !mWidget) {
+    return;
+  }
+
+  PWLOG("PluginWidgetParent::ShutdownCommon()\n");
+  mWidget->UnregisterPluginWindowForRemoteUpdates();
+  DebugOnly<nsresult> rv = mWidget->Destroy();
+  NS_ASSERTION(NS_SUCCEEDED(rv), "widget destroy failure");
+  mWidget = nullptr;
   mActorDestroyed = true;
-  PWLOG("PluginWidgetParent::ActorDestroy()\n");
+  unused << SendParentShutdown(aParentInitiated);
 }
 
 // Called by TabParent's Destroy() in response to an early tear down (Early
 // in that this is happening before layout in the child has had a chance
 // to destroy the child widget.) when the tab is closing. We will not receive
 // RecvDestroy here.
 void
 PluginWidgetParent::ParentDestroy()
 {
-  if (mActorDestroyed || !mWidget) {
-    return;
-  }
   PWLOG("PluginWidgetParent::ParentDestroy()\n");
-  mWidget->UnregisterPluginWindowForRemoteUpdates();
-  DebugOnly<nsresult> rv = mWidget->Destroy();
-  NS_ASSERTION(NS_SUCCEEDED(rv), "widget destroy failure");
-  mWidget = nullptr;
-  mActorDestroyed = true;
-  return;
+  ShutdownCommon(true);
 }
 
 // Called by the child when a plugin is torn down within a tab
 // normally.
 bool
 PluginWidgetParent::RecvDestroy()
 {
-  bool destroyed = mActorDestroyed;
-  ParentDestroy();
-  if (!destroyed) {
-    unused << SendParentShutdown();
-  }
+  PWLOG("PluginWidgetParent::RecvDestroy()\n");
+  ShutdownCommon(false);
   return true;
 }
 
 bool
 PluginWidgetParent::RecvSetFocus(const bool& aRaise)
 {
   ENSURE_CHANNEL;
   PWLOG("PluginWidgetParent::RecvSetFocus(%d)\n", aRaise);
--- a/dom/plugins/ipc/PluginWidgetParent.h
+++ b/dom/plugins/ipc/PluginWidgetParent.h
@@ -44,16 +44,18 @@ public:
 
   // Helper for compositor checks on the channel
   bool ActorDestroyed() { return mActorDestroyed; }
 
   // Called by PBrowser when it receives a Destroy() call from the child.
   void ParentDestroy();
 
 private:
+  void ShutdownCommon(bool aParentInitiated);
+
   // The tab our connection is associated with.
   mozilla::dom::TabParent* GetTabParent();
   // The chrome side native widget.
   nsCOMPtr<nsIWidget> mWidget;
 #if defined(MOZ_WIDGET_GTK)
   nsAutoPtr<nsPluginNativeWindowGtk> mWrapper;
 #endif
   bool mActorDestroyed;