[eric] crash: quiesce+detach outgoing webviews before dashboard-switch resetLayout (it unmounted every app/browser webview in one frame w/ CDP attached = GPU/browser SIGSEGV, the 'navigate away kills the app' self-quit)

This commit is contained in:
ciregenz
2026-07-28 23:24:21 -07:00
parent 4c483051b4
commit 028d9dcd62
4 changed files with 42 additions and 4 deletions
+4
View File
@@ -116,6 +116,10 @@ export function getWebview(browserId: string, tabId?: string): BrowserWebview |
return registry.get(makeKey(browserId, resolvedTabId));
}
export function getAllBrowserIds(): string[] {
return [...new Set([...registry.keys()].map((k) => k.split(':')[0]))];
}
export function getBrowserWebviews(browserId: string): BrowserWebview[] {
const out: BrowserWebview[] = [];
for (const [key, wv] of registry.entries()) {
@@ -0,0 +1,23 @@
import { getAllViewOutputIds } from '@/shared/viewWebviewRegistry';
import { getAllBrowserIds } from '@/shared/browserRegistry';
import { quiesceViewWebview } from '@/shared/viewTeardown';
import { detachBrowserCdp } from '@/shared/browserTeardown';
// Switching dashboards clears every card from the store in ONE reducer (resetLayout), so React
// unmounts all the outgoing app + browser <webview>s in a single frame. Ripping several live GPU
// surfaces out at once (app previews) or unmounting a browser with its CDP debugger still attached
// piles up "non-existent mailbox" errors and SIGSEGVs the GPU/browser process, taking the whole app
// down with no crash dump (the "navigate away and it quits itself" bug). Quiesce + detach the
// outgoing webviews ONE AT A TIME first, so only trivial surfaces are left to tear down. Bounded per
// item (the helpers self-cap), fail-open, and keep-alive browsers are skipped so they survive the
// switch with their session intact.
export async function prepareDashboardSwitch(keepBrowserIds: string[]): Promise<void> {
const keep = new Set(keepBrowserIds);
for (const outputId of getAllViewOutputIds()) {
await quiesceViewWebview(outputId);
}
for (const browserId of getAllBrowserIds()) {
if (keep.has(browserId)) continue;
await detachBrowserCdp(browserId);
}
}
@@ -11,6 +11,10 @@ export function registerViewWebview(outputId: string, wv: ViewWebview): void {
registry.set(outputId, wv);
}
export function getAllViewOutputIds(): string[] {
return [...registry.keys()];
}
export function unregisterViewWebview(outputId: string): void {
registry.delete(outputId);
}