fix(win): bound renderer launch-failed recovery (#8234)
This commit is contained in:
parent
76c0365110
commit
fa691a0dc8
|
|
@ -366,19 +366,22 @@ describe('shouldRecoverRendererAfterProcessGone', () => {
|
|||
).toBe(false)
|
||||
})
|
||||
|
||||
it('does not recover renderer startup and security launch failures', () => {
|
||||
it('recovers transient renderer launch failures', () => {
|
||||
expect(
|
||||
shouldRecoverRendererAfterProcessGone({
|
||||
reason: 'launch-failed',
|
||||
expectedTeardown: 'none'
|
||||
})
|
||||
).toBe(false)
|
||||
).toBe(true)
|
||||
expect(
|
||||
shouldRecoverRendererAfterProcessGone({
|
||||
reason: 'launch-failed',
|
||||
expectedTeardown: 'renderer-reload'
|
||||
})
|
||||
).toBe(false)
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it('does not recover renderer integrity failures', () => {
|
||||
expect(
|
||||
shouldRecoverRendererAfterProcessGone({
|
||||
reason: 'integrity-failure',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const RECOVERABLE_UTILITY_SERVICE_NAMES = new Set([
|
|||
'video_capture.mojom.VideoCaptureService'
|
||||
])
|
||||
const RECOVERABLE_CHILD_PROCESS_REASONS = new Set(['abnormal-exit', 'crashed', 'killed'])
|
||||
const NON_RECOVERABLE_RENDERER_REASONS = new Set(['integrity-failure', 'launch-failed'])
|
||||
const NON_RECOVERABLE_RENDERER_REASONS = new Set(['integrity-failure'])
|
||||
|
||||
function isWindowsControlTerminationExitCode(exitCode: number | null): boolean {
|
||||
if (exitCode === null) {
|
||||
|
|
@ -95,8 +95,9 @@ export function shouldRecoverRendererAfterProcessGone({
|
|||
if (expectedTeardown === 'app-shutdown') {
|
||||
return false
|
||||
}
|
||||
// Why: these mean Chromium could not start or trust the renderer process;
|
||||
// retrying the same BrowserWindow load can loop indefinitely on Windows.
|
||||
// Why: an integrity failure means Chromium cannot trust the renderer, so a
|
||||
// reload cannot safely recover it. Launch failures can be transient and are
|
||||
// bounded by the caller's renderer-recovery circuit breaker.
|
||||
if (NON_RECOVERABLE_RENDERER_REASONS.has(reason)) {
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ vi.mock('../browser/browser-manager', () => ({
|
|||
|
||||
import { createMainWindow, loadMainWindow } from './createMainWindow'
|
||||
import { ipcMain } from 'electron'
|
||||
import { shouldRecoverRendererAfterProcessGone } from '../crash-reporting/process-gone-classification'
|
||||
|
||||
function withPlatform<T>(platform: NodeJS.Platform, run: () => T): T {
|
||||
const original = process.platform
|
||||
|
|
@ -2703,6 +2704,48 @@ describe('createMainWindow', () => {
|
|||
consoleError.mockRestore()
|
||||
})
|
||||
|
||||
it('bounds renderer launch-failed recovery with the crash-loop breaker', () => {
|
||||
vi.useFakeTimers()
|
||||
|
||||
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const onRendererRecoveryExhausted = vi.fn()
|
||||
const { browserWindowInstance, windowHandlers } = createRendererRecoveryWindowHarness()
|
||||
|
||||
try {
|
||||
createMainWindow(null, {
|
||||
onRendererRecoveryExhausted,
|
||||
shouldRecoverRenderer: (details) =>
|
||||
shouldRecoverRendererAfterProcessGone({
|
||||
reason: details.reason,
|
||||
expectedTeardown: 'none'
|
||||
})
|
||||
})
|
||||
|
||||
const details = {
|
||||
reason: 'launch-failed',
|
||||
exitCode: 18
|
||||
} as Electron.RenderProcessGoneDetails
|
||||
const driveLaunchFailure = (): void => {
|
||||
windowHandlers['render-process-gone']?.({} as never, details)
|
||||
vi.advanceTimersByTime(250)
|
||||
}
|
||||
|
||||
driveLaunchFailure()
|
||||
driveLaunchFailure()
|
||||
driveLaunchFailure()
|
||||
expect(browserWindowInstance.loadFile).toHaveBeenCalledTimes(4)
|
||||
|
||||
driveLaunchFailure()
|
||||
expect(browserWindowInstance.loadFile).toHaveBeenCalledTimes(4)
|
||||
expect(onRendererRecoveryExhausted).toHaveBeenCalledOnce()
|
||||
expect(onRendererRecoveryExhausted).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ details, recentRecoveryCount: 3 })
|
||||
)
|
||||
} finally {
|
||||
consoleError.mockRestore()
|
||||
}
|
||||
})
|
||||
|
||||
function createStartupRevealWindowFixture() {
|
||||
const windowHandlers: Record<string, (...args: any[]) => void> = {}
|
||||
const webContents = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue