From 140b1c3ff880e86edcab9d99d641c53a13d3c6a7 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Tue, 16 Aug 2011 05:25:34 -0500 Subject: [PATCH] Bug 677711 - Kill plugin processes when the child detects the browser is hung. r=bsmedberg --- dom/plugins/ipc/PPluginModule.ipdl | 2 ++ dom/plugins/ipc/PluginModuleChild.cpp | 19 +++++++++++++++ dom/plugins/ipc/PluginModuleChild.h | 6 +++++ dom/plugins/ipc/PluginModuleParent.cpp | 32 ++++++++++++++++---------- modules/libpref/src/init/all.js | 5 ++++ 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/dom/plugins/ipc/PPluginModule.ipdl b/dom/plugins/ipc/PPluginModule.ipdl index 325a7273bf9..a0303c44ff2 100644 --- a/dom/plugins/ipc/PPluginModule.ipdl +++ b/dom/plugins/ipc/PPluginModule.ipdl @@ -112,6 +112,8 @@ child: nsString aDisplayName, nsString aIconPath); + async SetParentHangTimeout(uint32_t seconds); + parent: /** * This message is only used on X11 platforms. diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index c4fc9490585..44090a901a3 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -44,6 +44,7 @@ #endif #include "mozilla/plugins/PluginModuleChild.h" +#include "mozilla/ipc/SyncChannel.h" #ifdef MOZ_WIDGET_GTK2 #include @@ -513,6 +514,24 @@ PluginModuleChild::ExitedCxxStack() #endif +bool +PluginModuleChild::RecvSetParentHangTimeout(const uint32_t& aSeconds) +{ +#ifdef XP_WIN + SetReplyTimeoutMs(((aSeconds > 0) ? (1000 * aSeconds) : 0)); +#endif + return true; +} + +bool +PluginModuleChild::ShouldContinueFromReplyTimeout() +{ +#ifdef XP_WIN + NS_RUNTIMEABORT("terminating child process"); +#endif + return true; +} + bool PluginModuleChild::InitGraphics() { diff --git a/dom/plugins/ipc/PluginModuleChild.h b/dom/plugins/ipc/PluginModuleChild.h index 9252eff9644..2383c387ba1 100644 --- a/dom/plugins/ipc/PluginModuleChild.h +++ b/dom/plugins/ipc/PluginModuleChild.h @@ -111,6 +111,9 @@ protected: return MediateRace(parent, child); } + NS_OVERRIDE + virtual bool ShouldContinueFromReplyTimeout(); + // Implement the PPluginModuleChild interface virtual bool AnswerNP_GetEntryPoints(NPError* rv); virtual bool AnswerNP_Initialize(NativeThreadId* tid, NPError* rv); @@ -168,6 +171,9 @@ protected: const nsString& aDisplayName, const nsString& aIconPath); + virtual bool + RecvSetParentHangTimeout(const uint32_t& aSeconds); + virtual void ActorDestroy(ActorDestroyReason why); diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index aceb7492eee..a0fa0f341fb 100644 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -79,7 +79,8 @@ using namespace mozilla; using namespace mozilla::plugins; using namespace mozilla::plugins::parent; -static const char kTimeoutPref[] = "dom.ipc.plugins.timeoutSecs"; +static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs"; +static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs"; static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs"; template<> @@ -109,7 +110,7 @@ PluginModuleParent::LoadModule(const char* aFilePath) parent->Open(parent->mSubprocess->GetChannel(), parent->mSubprocess->GetChildProcessHandle()); - TimeoutChanged(kTimeoutPref, parent); + TimeoutChanged(kChildTimeoutPref, parent); return parent.forget(); } @@ -131,7 +132,8 @@ PluginModuleParent::PluginModuleParent(const char* aFilePath) NS_ERROR("Out of memory"); } - Preferences::RegisterCallback(TimeoutChanged, kTimeoutPref, this); + Preferences::RegisterCallback(TimeoutChanged, kChildTimeoutPref, this); + Preferences::RegisterCallback(TimeoutChanged, kParentTimeoutPref, this); } PluginModuleParent::~PluginModuleParent() @@ -156,7 +158,8 @@ PluginModuleParent::~PluginModuleParent() mSubprocess = nsnull; } - Preferences::UnregisterCallback(TimeoutChanged, kTimeoutPref, this); + Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this); + Preferences::UnregisterCallback(TimeoutChanged, kParentTimeoutPref, this); } #ifdef MOZ_CRASHREPORTER @@ -226,14 +229,17 @@ int PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule) { NS_ASSERTION(NS_IsMainThread(), "Wrong thead!"); - NS_ABORT_IF_FALSE(!strcmp(aPref, kTimeoutPref), - "unexpected pref callback"); - - PRInt32 timeoutSecs = Preferences::GetInt(kTimeoutPref, 0); - int32 timeoutMs = (timeoutSecs > 0) ? (1000 * timeoutSecs) : - SyncChannel::kNoTimeout; - - static_cast(aModule)->SetReplyTimeoutMs(timeoutMs); + if (!strcmp(aPref, kChildTimeoutPref)) { + // The timeout value used by the parent for children + PRInt32 timeoutSecs = Preferences::GetInt(kChildTimeoutPref, 0); + int32 timeoutMs = (timeoutSecs > 0) ? (1000 * timeoutSecs) : + SyncChannel::kNoTimeout; + static_cast(aModule)->SetReplyTimeoutMs(timeoutMs); + } else if (!strcmp(aPref, kParentTimeoutPref)) { + // The timeout value used by the child for its parent + PRInt32 timeoutSecs = Preferences::GetInt(kParentTimeoutPref, 0); + static_cast(aModule)->SendSetParentHangTimeout(timeoutSecs); + } return 0; } @@ -921,6 +927,8 @@ PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance, return NS_ERROR_FAILURE; } + TimeoutChanged(kParentTimeoutPref, this); + return NS_OK; } diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 02860dbd892..0cdce378cdd 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -1453,6 +1453,10 @@ pref("dom.max_script_run_time", 10); // How long a plugin is allowed to process a synchronous IPC message // before we consider it "hung". pref("dom.ipc.plugins.timeoutSecs", 45); +// How long a plugin process will wait for a response from the parent +// to a synchronous request before terminating itself. After this +// point the child assumes the parent is hung. +pref("dom.ipc.plugins.parentTimeoutSecs", 15); // How long a plugin launch is allowed to take before // we consider it failed. pref("dom.ipc.plugins.processLaunchTimeoutSecs", 45); @@ -1460,6 +1464,7 @@ pref("dom.ipc.plugins.processLaunchTimeoutSecs", 45); // No timeout in DEBUG builds pref("dom.ipc.plugins.timeoutSecs", 0); pref("dom.ipc.plugins.processLaunchTimeoutSecs", 0); +pref("dom.ipc.plugins.parentTimeoutSecs", 0); #endif // Disable oopp for standard java. They run their own process isolation (which