diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 47527ece2319..15e6b0aaba93 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -10686,6 +10686,29 @@ nsContentUtils::GetSourceMapURL(nsIHttpChannel* aChannel, nsACString& aResult) return NS_SUCCEEDED(rv); } +/* static */ bool +nsContentUtils::IsMessageInputEvent(const IPC::Message& aMsg) +{ + if ((aMsg.type() & mozilla::dom::PBrowser::PBrowserStart) + == mozilla::dom::PBrowser::PBrowserStart) { + switch (aMsg.type()) { + case mozilla::dom::PBrowser::Msg_RealMouseMoveEvent__ID: + case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID: + case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID: + case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID: + case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID: + case mozilla::dom::PBrowser::Msg_RealTouchMoveEvent__ID: + case mozilla::dom::PBrowser::Msg_RealDragEvent__ID: + case mozilla::dom::PBrowser::Msg_UpdateDimensions__ID: + case mozilla::dom::PBrowser::Msg_MouseEvent__ID: + case mozilla::dom::PBrowser::Msg_KeyEvent__ID: + case mozilla::dom::PBrowser::Msg_SetDocShellIsActive__ID: + return true; + } + } + return false; +} + static const char* kUserInteractionInactive = "user-interaction-inactive"; static const char* kUserInteractionActive = "user-interaction-active"; diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 79084ff586a6..e29a181987ff 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -3126,6 +3126,13 @@ public: */ static bool GetSourceMapURL(nsIHttpChannel* aChannel, nsACString& aResult); + /** + * Returns true if the passed-in mesasge is a pending InputEvent. + * + * @param aMsg The message to check + */ + static bool IsMessageInputEvent(const IPC::Message& aMsg); + private: static bool InitializeEventTable(); diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 2bbf599922a5..6dfc0a8680bf 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -491,6 +491,29 @@ private: } }; +#ifdef NIGHTLY_BUILD +/** + * The singleton of this class is registered with the HangMonitor as an + * annotator, so that the hang monitor can record whether or not there were + * pending input events when the thread hung. + */ +class PendingInputEventHangAnnotator final + : public HangMonitor::Annotator +{ +public: + virtual void AnnotateHang(HangMonitor::HangAnnotations& aAnnotations) + { + int32_t pending = ContentChild::GetSingleton()->GetPendingInputEvents(); + if (pending > 0) { + aAnnotations.AddAnnotation(NS_LITERAL_STRING("PendingInput"), pending); + } + } + + static PendingInputEventHangAnnotator sSingleton; +}; +PendingInputEventHangAnnotator PendingInputEventHangAnnotator::sSingleton; +#endif + NS_IMPL_ISUPPORTS(BackgroundChildPrimer, nsIIPCBackgroundChildCreateCallback) ContentChild* ContentChild::sSingleton; @@ -638,6 +661,10 @@ ContentChild::Init(MessageLoop* aIOLoop, SetProcessName(NS_LITERAL_STRING("Web Content")); +#ifdef NIGHTLY_BUILD + HangMonitor::RegisterAnnotator(PendingInputEventHangAnnotator::sSingleton); +#endif + return true; } @@ -2930,6 +2957,10 @@ ContentChild::RecvShutdown() mShuttingDown = true; +#ifdef NIGHTLY_BUILD + HangMonitor::UnregisterAnnotator(PendingInputEventHangAnnotator::sSingleton); +#endif + if (mPolicy) { mPolicy->Deactivate(); mPolicy = nullptr; @@ -3580,6 +3611,33 @@ ContentChild::GetSpecificMessageEventTarget(const Message& aMsg) return nullptr; } +#ifdef NIGHTLY_BUILD +void +ContentChild::OnChannelReceivedMessage(const Message& aMsg) +{ + if (nsContentUtils::IsMessageInputEvent(aMsg)) { + mPendingInputEvents++; + } +} + +PContentChild::Result +ContentChild::OnMessageReceived(const Message& aMsg) +{ + if (nsContentUtils::IsMessageInputEvent(aMsg)) { + DebugOnly prevEvts = mPendingInputEvents--; + MOZ_ASSERT(prevEvts > 0); + } + + return PContentChild::OnMessageReceived(aMsg); +} + +PContentChild::Result +ContentChild::OnMessageReceived(const Message& aMsg, Message*& aReply) +{ + return PContentChild::OnMessageReceived(aMsg, aReply); +} +#endif + } // namespace dom #if !defined(XP_WIN) diff --git a/dom/ipc/ContentChild.h b/dom/ipc/ContentChild.h index 73d41c783804..2f6f36640741 100644 --- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -681,6 +681,17 @@ public: nsTArray&& aPluginTags, nsTArray&& aFakePluginTags) override; +#ifdef NIGHTLY_BUILD + // Fetch the current number of pending input events. + // + // NOTE: This method performs an atomic read, and is safe to call from all threads. + uint32_t + GetPendingInputEvents() + { + return mPendingInputEvents; + } +#endif + private: static void ForceKillTimerCallback(nsITimer* aTimer, void* aClosure); void StartForceKillTimer(); @@ -695,6 +706,17 @@ private: virtual already_AddRefed GetSpecificMessageEventTarget(const Message& aMsg) override; +#ifdef NIGHTLY_BUILD + virtual void + OnChannelReceivedMessage(const Message& aMsg) override; + + virtual PContentChild::Result + OnMessageReceived(const Message& aMsg) override; + + virtual PContentChild::Result + OnMessageReceived(const Message& aMsg, Message*& aReply) override; +#endif + InfallibleTArray > mAlertObservers; RefPtr mConsoleListener; @@ -765,6 +787,11 @@ private: mozilla::Atomic mShuttingDown; +#ifdef NIGHTLY_BUILD + // NOTE: This member is atomic because it can be accessed from off-main-thread. + mozilla::Atomic mPendingInputEvents; +#endif + DISALLOW_EVIL_CONSTRUCTORS(ContentChild); }; diff --git a/widget/PuppetWidget.cpp b/widget/PuppetWidget.cpp index bc0fe77e5cc6..defb358e2656 100644 --- a/widget/PuppetWidget.cpp +++ b/widget/PuppetWidget.cpp @@ -1404,23 +1404,9 @@ PuppetWidget::HasPendingInputEvent() mTabChild->GetIPCChannel()->PeekMessages( [&ret](const IPC::Message& aMsg) -> bool { - if ((aMsg.type() & mozilla::dom::PBrowser::PBrowserStart) - == mozilla::dom::PBrowser::PBrowserStart) { - switch (aMsg.type()) { - case mozilla::dom::PBrowser::Msg_RealMouseMoveEvent__ID: - case mozilla::dom::PBrowser::Msg_RealMouseButtonEvent__ID: - case mozilla::dom::PBrowser::Msg_RealKeyEvent__ID: - case mozilla::dom::PBrowser::Msg_MouseWheelEvent__ID: - case mozilla::dom::PBrowser::Msg_RealTouchEvent__ID: - case mozilla::dom::PBrowser::Msg_RealTouchMoveEvent__ID: - case mozilla::dom::PBrowser::Msg_RealDragEvent__ID: - case mozilla::dom::PBrowser::Msg_UpdateDimensions__ID: - case mozilla::dom::PBrowser::Msg_MouseEvent__ID: - case mozilla::dom::PBrowser::Msg_KeyEvent__ID: - case mozilla::dom::PBrowser::Msg_SetDocShellIsActive__ID: - ret = true; - return false; // Stop peeking. - } + if (nsContentUtils::IsMessageInputEvent(aMsg)) { + ret = true; + return false; // Stop peeking. } return true; }