← All issues

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

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.

🔒

New cross-process lifecycle paths and IPC surface introduce several edge cases worth security investigation.

Subscribe to read more