fix: report renderer hangs independently of system sleep and window visibility - #53529
Open
codebytere wants to merge 7 commits into
Open
fix: report renderer hangs independently of system sleep and window visibility#53529codebytere wants to merge 7 commits into
codebytere wants to merge 7 commits into
Conversation
The input event ack timeout that drives the `unresponsive` event runs on base::TimeTicks, which keeps counting through system sleep on Windows (QPC) but stands still on macOS and Linux. A timeout armed before the machine sleeps therefore fires the moment it wakes, while every process is still paging back in, and the renderer is reported unresponsive (RenderWidgetHostImpl::OnInputEventAckTimeout -> RendererUnresponsive); apps commonly answer that by killing and reloading the renderer. The GPU watchdog already pauses across suspend for the same reason (GpuWatchdogThread is a PowerSuspendObserver); the renderer hang monitor has no power awareness. WebContents::RendererUnresponsive() now checks base::PowerMonitor: when the system is suspended, or resumed less than input::kHungRendererDelay ago, it runs the hang monitor restarter it is handed instead of emitting the event, so a renderer that is still stuck a full delay after the wake is reported as before. The testing binding gains simulatePowerEvent() so the spec can drive base::PowerMonitor's suspend/resume.
RenderWidgetHostImpl::WasHidden() stopped the hang monitor with StopInputEventAckTimeout(), which also declares the renderer responsive. A window that hangs and is then minimized, occluded or screen-locked therefore emitted `responsive` without recovering, and the real recovery later emitted nothing, so neither event could be trusted. Hiding now pauses the timeout instead (folded into refactor_unfilter_unresponsive_events.patch, which exists to make these events usable from Electron); showing the window re-arms it and a real input ack still emits `responsive`.
…r-resume # Conflicts: # shell/common/api/electron_api_testing.cc
MarshallOfSound
approved these changes
Sep 5, 2026
…r-resume # Conflicts: # patches/chromium/revert_partial_remove_unused_prehandlemouseevent.patch
…r-resume # Conflicts: # patches/chromium/revert_partial_remove_unused_prehandlemouseevent.patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description of Change
The
unresponsive/responsiveevents onwebContentsnow reflect the renderer, not system sleep or window visibility. Two cases produced events that had nothing to do with the renderer's state, and apps that reload or kill a renderer onunresponsive(or wait forresponsive) acted on them:After the system wakes. The input event ack timeout behind
unresponsiveruns onbase::TimeTicks, which keeps counting through sleep on Windows (QPC) but stands still on macOS and Linux. A timeout armed before the machine sleeps therefore fires the moment it wakes, while every process is still paging back in, and the renderer is reported unresponsive. Chromium's GPU watchdog already pauses across suspend for this reason; the renderer hang monitor has no power awareness.WebContents::RendererUnresponsive()now checksbase::PowerMonitor: while the system is suspended, or withininput::kHungRendererDelayof the last resume, it runs the hang-monitor restarter it is handed instead of emitting, so a renderer that is still stuck a full delay after the wake is reported as before.When a hung window is hidden.
RenderWidgetHostImpl::WasHidden()stopped the timeout withStopInputEventAckTimeout(), which also declares the renderer responsive. Minimizing, occluding or screen-locking a hung window therefore emittedresponsivewith no recovery behind it and cleared the unresponsive state, so the real recovery later emitted nothing.WasHidden()now pauses the timeout without touching responsiveness (aPauseInputEventAckTimeout()split out ofStopInputEventAckTimeout(), added to the existingrefactor_unfilter_unresponsive_events.patch);WasShown()re-arms it for a widget that is still hung, and a real input ack still emitsresponsive, hidden or not. Chrome relies on the old behavior only to dismiss its hung-page dialog on tab backgrounding, which Electron does not build.unresponsive~1 s after wakeresponsiveimmediately; nothing when it actually recoversunresponsiveagain when shown if still hung;responsivewhen it recoversThe testing-only binding gains
simulatePowerEvent('suspend' | 'resume')(drivesbase::PowerMonitorSource::ProcessPowerEvent) so the spec can exercise the resume path.Checklist
npm testpasses (newwebContents module > unresponsive eventcases: not emitted within a hang delay of a resume; noresponsiveon hide,unresponsiveagain on show,responsiveon recovery; baseline hang still reported; each fails with its fix reverted)unresponsive/responsivedocs unchanged)Release Notes
Notes: Fixed
webContentsemittingunresponsiveright after the system wakes from sleep on Windows, and emittingresponsivewhen a hung window was hidden rather than when it recovered.