diff --git a/dom/plugins/ipc/PluginHangUIParent.cpp b/dom/plugins/ipc/PluginHangUIParent.cpp index d41e5f48afb9..5e8e63d00b46 100644 --- a/dom/plugins/ipc/PluginHangUIParent.cpp +++ b/dom/plugins/ipc/PluginHangUIParent.cpp @@ -356,6 +356,7 @@ PluginHangUIParent::RecvUserResponse(const unsigned int& aResponse) mModule->TerminateChildProcess(mMainThreadMessageLoop); responseCode = 1; } else if(aResponse & HANGUI_USER_RESPONSE_CONTINUE) { + mModule->OnHangUIContinue(); // User clicked Continue responseCode = 2; } else { diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 96329772addf..dd1b203afe07 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -133,6 +133,7 @@ PluginModuleParent::PluginModuleParent(const char* aFilePath) , mNPNIface(nullptr) , mPlugin(nullptr) , mTaskFactory(MOZ_THIS_IN_INITIALIZER_LIST()) + , mHangAnnotationFlags(0) #ifdef XP_WIN , mPluginCpuUsageOnHang() , mHangUIParent(nullptr) @@ -160,6 +161,8 @@ PluginModuleParent::PluginModuleParent(const char* aFilePath) #ifdef MOZ_ENABLE_PROFILER_SPS InitPluginProfiling(); #endif + + mozilla::HangMonitor::RegisterAnnotator(*this); } PluginModuleParent::~PluginModuleParent() @@ -203,6 +206,8 @@ PluginModuleParent::~PluginModuleParent() mHangUIParent = nullptr; } #endif + + mozilla::HangMonitor::UnregisterAnnotator(*this); } #ifdef MOZ_CRASHREPORTER @@ -224,20 +229,8 @@ PluginModuleParent::WriteExtraDataForMinidump(AnnotationTable& notes) filePos++; notes.Put(NS_LITERAL_CSTRING("PluginFilename"), CS(pluginFile.substr(filePos).c_str())); - nsCString pluginName; - nsCString pluginVersion; - - nsRefPtr ph = nsPluginHost::GetInst(); - if (ph) { - nsPluginTag* tag = ph->TagForPlugin(mPlugin); - if (tag) { - pluginName = tag->mName; - pluginVersion = tag->mVersion; - } - } - - notes.Put(NS_LITERAL_CSTRING("PluginName"), pluginName); - notes.Put(NS_LITERAL_CSTRING("PluginVersion"), pluginVersion); + notes.Put(NS_LITERAL_CSTRING("PluginName"), mPluginName); + notes.Put(NS_LITERAL_CSTRING("PluginVersion"), mPluginVersion); CrashReporterParent* crashReporter = CrashReporter(); if (crashReporter) { @@ -389,13 +382,52 @@ GetProcessCpuUsage(const InfallibleTArray& processHandles, } // anonymous namespace +#endif // #ifdef XP_WIN + +void +PluginModuleParent::EnteredCxxStack() +{ + mHangAnnotationFlags |= kInPluginCall; +} + void PluginModuleParent::ExitedCxxStack() { + mHangAnnotationFlags = 0; +#ifdef XP_WIN FinishHangUI(); +#endif } -#endif // #ifdef XP_WIN +/** + * This function is always called by the HangMonitor thread. + */ +void +PluginModuleParent::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) +{ + uint32_t flags = mHangAnnotationFlags; + if (flags) { + /* We don't actually annotate anything specifically for kInPluginCall; + we use it to determine whether to annotate other things. It will + be pretty obvious from the ChromeHang stack that we're in a plugin + call when the hang occurred. */ + if (flags & kHangUIShown) { + aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIShown"), + true); + } + if (flags & kHangUIContinued) { + aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIContinued"), + true); + } + if (flags & kHangUIDontShow) { + aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIDontShow"), + true); + } + aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginName"), mPluginName); + aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginVersion"), + mPluginVersion); + } +} #ifdef MOZ_CRASHREPORTER_INJECTOR static bool @@ -531,6 +563,23 @@ PluginModuleParent::TerminateChildProcess(MessageLoop* aMsgLoop) NS_WARNING("failed to kill subprocess!"); } +bool +PluginModuleParent::GetPluginDetails(nsACString& aPluginName, + nsACString& aPluginVersion) +{ + nsRefPtr host = nsPluginHost::GetInst(); + if (!host) { + return false; + } + nsPluginTag* pluginTag = host->TagForPlugin(mPlugin); + if (!pluginTag) { + return false; + } + aPluginName = pluginTag->mName; + aPluginVersion = pluginTag->mVersion; + return true; +} + #ifdef XP_WIN void PluginModuleParent::EvaluateHangUIState(const bool aReset) @@ -566,21 +615,6 @@ PluginModuleParent::EvaluateHangUIState(const bool aReset) SetChildTimeout(autoStopSecs); } -bool -PluginModuleParent::GetPluginName(nsAString& aPluginName) -{ - nsRefPtr host = nsPluginHost::GetInst(); - if (!host) { - return false; - } - nsPluginTag* pluginTag = host->TagForPlugin(mPlugin); - if (!pluginTag) { - return false; - } - CopyUTF8toUTF16(pluginTag->mName, aPluginName); - return true; -} - bool PluginModuleParent::LaunchHangUI() { @@ -593,7 +627,12 @@ PluginModuleParent::LaunchHangUI() return false; } if (mHangUIParent->DontShowAgain()) { - return !mHangUIParent->WasLastHangStopped(); + mHangAnnotationFlags |= kHangUIDontShow; + bool wasLastHangStopped = mHangUIParent->WasLastHangStopped(); + if (!wasLastHangStopped) { + mHangAnnotationFlags |= kHangUIContinued; + } + return !wasLastHangStopped; } delete mHangUIParent; mHangUIParent = nullptr; @@ -601,12 +640,9 @@ PluginModuleParent::LaunchHangUI() mHangUIParent = new PluginHangUIParent(this, Preferences::GetInt(kHangUITimeoutPref, 0), Preferences::GetInt(kChildTimeoutPref, 0)); - nsAutoString pluginName; - if (!GetPluginName(pluginName)) { - return false; - } - bool retval = mHangUIParent->Init(pluginName); + bool retval = mHangUIParent->Init(NS_ConvertUTF8toUTF16(mPluginName)); if (retval) { + mHangAnnotationFlags |= kHangUIShown; /* Once the UI is shown we switch the timeout over to use kChildTimeoutPref, allowing us to terminate a hung plugin after kChildTimeoutPref seconds if the user doesn't respond to @@ -636,6 +672,12 @@ PluginModuleParent::FinishHangUI() } } } + +void +PluginModuleParent::OnHangUIContinue() +{ + mHangAnnotationFlags |= kHangUIContinued; +} #endif // XP_WIN #ifdef MOZ_CRASHREPORTER @@ -1263,6 +1305,10 @@ PluginModuleParent::NPP_New(NPMIMEType pluginType, NPP instance, return NS_ERROR_FAILURE; } + if (mPluginName.IsEmpty()) { + GetPluginDetails(mPluginName, mPluginVersion); + } + // create the instance on the other side InfallibleTArray names; InfallibleTArray values; diff --git a/dom/plugins/ipc/PluginModuleParent.h b/dom/plugins/ipc/PluginModuleParent.h index 91c0dcc1bf22..47f152af38bf 100644 --- a/dom/plugins/ipc/PluginModuleParent.h +++ b/dom/plugins/ipc/PluginModuleParent.h @@ -9,6 +9,7 @@ #include "base/process.h" #include "mozilla/FileUtils.h" +#include "mozilla/HangMonitor.h" #include "mozilla/PluginLibrary.h" #include "mozilla/plugins/ScopedMethodFactory.h" #include "mozilla/plugins/PluginProcessParent.h" @@ -59,6 +60,7 @@ class PluginModuleParent #ifdef MOZ_CRASHREPORTER_INJECTOR , public CrashReporter::InjectorCrashCallback #endif + , public mozilla::HangMonitor::Annotator { private: typedef mozilla::PluginLibrary PluginLibrary; @@ -112,9 +114,22 @@ public: void TerminateChildProcess(MessageLoop* aMsgLoop); -#ifdef XP_WIN - void + virtual void + EnteredCxxStack() MOZ_OVERRIDE; + + virtual void ExitedCxxStack() MOZ_OVERRIDE; + + virtual void + AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) MOZ_OVERRIDE; + +#ifdef XP_WIN + /** + * Called by Plugin Hang UI to notify that the user has clicked continue. + * Used for chrome hang annotations. + */ + void + OnHangUIContinue(); #endif // XP_WIN protected: @@ -287,6 +302,16 @@ private: nsString mBrowserDumpID; nsString mHangID; nsRefPtr mProfilerObserver; + enum HangAnnotationFlags + { + kInPluginCall = (1u << 0), + kHangUIShown = (1u << 1), + kHangUIContinued = (1u << 2), + kHangUIDontShow = (1u << 3) + }; + Atomic mHangAnnotationFlags; + nsCString mPluginName; + nsCString mPluginVersion; #ifdef XP_WIN InfallibleTArray mPluginCpuUsageOnHang; PluginHangUIParent *mHangUIParent; @@ -307,9 +332,6 @@ private: void EvaluateHangUIState(const bool aReset); - bool - GetPluginName(nsAString& aPluginName); - /** * Launches the Plugin Hang UI. * @@ -327,6 +349,9 @@ private: FinishHangUI(); #endif + bool + GetPluginDetails(nsACString& aPluginName, nsACString& aPluginVersion); + #ifdef MOZ_X11 // Dup of plugin's X socket, used to scope its resources to this // object instead of the plugin process's lifetime