Multi-process BFCache suspension for Site Isolation
41894db
Source/WebKit/UIProcess/SuspendedPageProxy.cpp
+void SuspendedPageProxy::startSuspension(std::optional<BackForwardFrameItemIdentifier> mainFrameItemID)
+{
+ ASSERT(m_suspensionState == SuspensionState::BeforeStart);
+ ASSERT(!m_browsingContextGroup->hasMultiplePages());
+
+ m_process->addSuspendedPageProxy(*this);
+ m_suspensionState = SuspensionState::Suspending;
+
+ if (mainFrameItemID)
+ suspendSubframeProcesses(*mainFrameItemID);
+ else
+ m_allSubframesSuspended = true;
+
+ m_messageReceiverRegistration.startReceivingMessages(m_process, m_webPageID, *this, *this);
+ m_suspensionTimeoutTimer.startOneShot(suspensionTimeout);
+ sendWithAsyncReply(Messages::WebPage::SetIsSuspended(true), [weakThis = WeakPtr { *this }](std::optional<bool> didSuspend) {
+ RefPtr protectedThis = weakThis.get();
+ if (!protectedThis || !didSuspend)
+ return;
+ protectedThis->didProcessRequestToSuspend(*didSuspend ? SuspensionState::Suspended : SuspensionState::FailedToSuspend);
+ });
+}
Source/WebKit/UIProcess/SuspendedPageProxy.cpp
+void SuspendedPageProxy::suspendSubframeProcesses(BackForwardFrameItemIdentifier mainFrameItemID)
+{
+ auto aggregator = MainRunLoopSuccessCallbackAggregator::create([weakThis = WeakPtr { *this }](bool success) {
+ RefPtr protectedThis = weakThis.get();
+ if (!protectedThis || protectedThis->m_suspensionState != SuspensionState::Suspending)
+ return;
+ if (!success) {
+ protect(protectedThis->backForwardCache())->removeEntry(*protectedThis);
+ return;
+ }
+ protectedThis->m_allSubframesSuspended = true;
+ protectedThis->maybeCompleteSuspension();
+ });
+
+ m_browsingContextGroup->forEachRemotePage(*page, [suspendedPage = Ref { *this }, &aggregator, mainFrameItemID](auto& remotePage) {
+ Ref process = remotePage.siteIsolatedProcess();
+ process->addSuspendedPageProxy(suspendedPage);
+ process->sendWithAsyncReply(Messages::WebPage::SetSubframesSuspended(true, mainFrameItemID), aggregator->chain(), remotePage.identifierInSiteIsolatedProcess());
+ });
+}
BFCache preserves a fully live page snapshot on navigation away, enabling instant back/forward restoration. With Site Isolation, cross-origin iframes run in separate WebProcess instances, each with their own per-process BackForwardCache singleton. Previously, BFCache entry suspension was entirely single-process.
This commit extends SuspendedPageProxy in the UIProcess to act as a coordinator: it sends a new SetSubframesSuspended IPC message to each subframe's WebProcess carrying the main frame's BackForwardFrameItemIdentifier (a stable per-navigation-entry key) so each can store its CachedPage under that shared key. A CallbackAggregator tracks completion across all processes; if any subframe fails to suspend, the BFCache entry is removed and subframe processes are torn down.
UIProcess WebProcess (main) WebProcess (subframe N)
│ │ │
├─ startSuspension() │ │
│ │ │ │
│ ├──► SetIsSuspended(true) ────►│ addIfCacheable() │
│ │ │ (HistoryItem path) │
│ │ │ │
│ ├──► SetSubframesSuspended ────┼───────────────────────►│
│ │ (mainFrameItemIdentifier) │ │ addIfCacheable(id, page)
│ │ │ │
│ └─ CallbackAggregator tracks all completions │
│ │ │ │
│ any fail? ◄───────────────┴────────────────────────┘
│ └──► removeEntry(*this)
│ teardown subframe processes
Significance
This is a major architectural expansion of BFCache into the Site Isolation world, wiring UIProcess lifecycle coordination across multiple WebProcesses simultaneously — new IPC surface, cross-process shared identifiers, and new teardown paths in security-critical navigation infrastructure.
Audit directions
Aaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaa a Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaa Aa Aaaaaaaaaaa Aaa Aaaaaaaaaa Aaaaaa a Aaaaaaaaaaaa Aaaaa Aaaa Aaa Aaaaaaa Aaaaaaaaaa Aaaaaaaaaa a a Aaaaaaaaaaa Aaaaaaaaaa Aaaaa Aaaa Aaaaaaaaaa Aaaaaaaaa Aaaaaaaaaa Aa Aaaaaa Aaaaaaaaaa Aaaaaa Aaaaaaaa Aaa Aaaaaaaaa Aa Aaaaaaa Aaaaaaa Aa Aaaaaaaa Aaaa Aa Aa Aaaa Aaa Aaaaaaaaaaaaaaaaaaaa Aaaaaa Aaaaaaaaaaaaa Aaaaa Aaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaa Aa Aaaa Aaaa Aaaaaa Aaa Aaaaaaaaa Aaaaaaaa Aaaaaaaaa Aaa Aaaaaaaaa Aaaaa Aaaaaaaaa Aaaaa Aaaaaa Aaa Aaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaa Aa a Aaaaaaaa Aaa a Aaaaaaaaaaaaaa Aaa Aaaaaaa Aaaaaaaaa Aaaa Aaaaaaa Aaa Aaaa Aaaaaa Aaaaaaaaa a Aaa Aaaa Aaaaaaa Aaaaaaaa Aaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaa Aa Aaaaaa Aa Aaaaaa Aaaa Aaaaaaaa Aa Aaaaaaaa Aaa Aaaaaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaa Aaaaaaaa Aaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaaaaaa Aaaaaaaa Aaaaaaaa a Aaaaaaaaaaaa Aaaaaaaaa Aa a Aaaaaaaa Aaaaaaa Aaaaa Aaa Aaaaaaaaa Aaaaaaaaa Aaa Aaaaa Aaaaaaaa Aaaaa Aaaaaa Aaaaa Aaaaa Aaaaaaaaaaa Aaa Aaaaaaaaa Aaaaaaaa
🔒New cross-process lifecycle paths and IPC surface introduce several edge cases worth security investigation.
Subscribe to read more