Close service worker database on network process suspension
authoryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Apr 2019 23:37:17 +0000 (23:37 +0000)
committeryouenn@apple.com <youenn@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Apr 2019 23:37:17 +0000 (23:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=196623
<rdar://problem/48930869>

Reviewed by Alex Christensen.

Source/WebCore:

Add suspend/resume support to SWServer.
On suspend, close the service worker database and stop pushing for changes.
On resume, push changes if needed.

* workers/service/server/RegistrationDatabase.cpp:
(WebCore::RegistrationDatabase::close):
* workers/service/server/RegistrationDatabase.h:
(WebCore::RegistrationDatabase::isClosed const): Deleted.
* workers/service/server/RegistrationStore.cpp:
(WebCore::RegistrationStore::closeDatabase):
* workers/service/server/RegistrationStore.cpp:
(WebCore::RegistrationStore::pushChangesToDatabase):
(WebCore::RegistrationStore::clearAll):
(WebCore::RegistrationStore::startSuspension):
(WebCore::RegistrationStore::endSuspension):
* workers/service/server/RegistrationStore.h:
* workers/service/server/SWServer.cpp:
(WebCore::SWServer::startSuspension):
(WebCore::SWServer::endSuspension):
* workers/service/server/SWServer.h:

Source/WebKit:

Close service worker database when preparing to suspend.
On resume, push changes if any is needed.

* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::actualPrepareToSuspend):
(WebKit::NetworkProcess::cancelPrepareToSuspend):
(WebKit::NetworkProcess::processDidResume):
* UIProcess/API/Cocoa/WKProcessPool.mm:
(-[WKProcessPool _sendNetworkProcessWillSuspendImminently]):
(-[WKProcessPool _sendNetworkProcessDidResume]):
* UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
* UIProcess/Network/NetworkProcessProxy.h:
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::sendNetworkProcessWillSuspendImminently):
(WebKit::WebProcessPool::sendNetworkProcessDidResume):
* UIProcess/WebProcessPool.h:

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@244097 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
Source/WebCore/ChangeLog
Source/WebCore/workers/service/server/RegistrationDatabase.cpp
Source/WebCore/workers/service/server/RegistrationDatabase.h
Source/WebCore/workers/service/server/RegistrationStore.cpp
Source/WebCore/workers/service/server/RegistrationStore.h
Source/WebCore/workers/service/server/SWServer.cpp
Source/WebCore/workers/service/server/SWServer.h
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/NetworkProcess.cpp
Source/WebKit/NetworkProcess/NetworkProcess.h
Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm
Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h
Source/WebKit/UIProcess/Network/NetworkProcessProxy.h
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/UIProcess/WebProcessPool.h
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm

index e8ad4e6..a9351bf 100644 (file)
@@ -1,3 +1,32 @@
+2019-04-09  Youenn Fablet  <youenn@apple.com>
+
+        Close service worker database on network process suspension
+        https://bugs.webkit.org/show_bug.cgi?id=196623
+        <rdar://problem/48930869>
+
+        Reviewed by Alex Christensen.
+
+        Add suspend/resume support to SWServer.
+        On suspend, close the service worker database and stop pushing for changes.
+        On resume, push changes if needed.
+
+        * workers/service/server/RegistrationDatabase.cpp:
+        (WebCore::RegistrationDatabase::close):
+        * workers/service/server/RegistrationDatabase.h:
+        (WebCore::RegistrationDatabase::isClosed const): Deleted.
+        * workers/service/server/RegistrationStore.cpp:
+        (WebCore::RegistrationStore::closeDatabase):
+        * workers/service/server/RegistrationStore.cpp:
+        (WebCore::RegistrationStore::pushChangesToDatabase):
+        (WebCore::RegistrationStore::clearAll):
+        (WebCore::RegistrationStore::startSuspension):
+        (WebCore::RegistrationStore::endSuspension):
+        * workers/service/server/RegistrationStore.h:
+        * workers/service/server/SWServer.cpp:
+        (WebCore::SWServer::startSuspension):
+        (WebCore::SWServer::endSuspension):
+        * workers/service/server/SWServer.h:
+
 2019-04-09  Justin Fan  <justin_fan@apple.com>
 
         [Web GPU] GPURenderPassEncoder updates: setBlendColor, setViewport, setScissorRect
 2019-04-09  Justin Fan  <justin_fan@apple.com>
 
         [Web GPU] GPURenderPassEncoder updates: setBlendColor, setViewport, setScissorRect
index 41e8055..1c78312 100644 (file)
@@ -118,6 +118,8 @@ RegistrationDatabase::~RegistrationDatabase()
 
 void RegistrationDatabase::postTaskToWorkQueue(Function<void()>&& task)
 {
 
 void RegistrationDatabase::postTaskToWorkQueue(Function<void()>&& task)
 {
+    ASSERT(isMainThread());
+
     m_workQueue->dispatch([protectedThis = makeRef(*this), task = WTFMove(task)]() mutable {
         task();
     });
     m_workQueue->dispatch([protectedThis = makeRef(*this), task = WTFMove(task)]() mutable {
         task();
     });
@@ -283,6 +285,14 @@ void RegistrationDatabase::pushChanges(Vector<ServiceWorkerContextData>&& datas,
     });
 }
 
     });
 }
 
+void RegistrationDatabase::close(CompletionHandler<void()>&& completionHandler)
+{
+    postTaskToWorkQueue([this, completionHandler = WTFMove(completionHandler)]() mutable {
+        m_database = nullptr;
+        callOnMainThread(WTFMove(completionHandler));
+    });
+}
+
 void RegistrationDatabase::clearAll(CompletionHandler<void()>&& completionHandler)
 {
     postTaskToWorkQueue([this, completionHandler = WTFMove(completionHandler)]() mutable {
 void RegistrationDatabase::clearAll(CompletionHandler<void()>&& completionHandler)
 {
     postTaskToWorkQueue([this, completionHandler = WTFMove(completionHandler)]() mutable {
index e9daf91..ff5367b 100644 (file)
@@ -52,10 +52,10 @@ public:
 
     ~RegistrationDatabase();
 
 
     ~RegistrationDatabase();
 
-    bool isClosed() const { return !m_database; }
 
     void pushChanges(Vector<ServiceWorkerContextData>&&, CompletionHandler<void()>&&);
     void clearAll(CompletionHandler<void()>&&);
 
     void pushChanges(Vector<ServiceWorkerContextData>&&, CompletionHandler<void()>&&);
     void clearAll(CompletionHandler<void()>&&);
+    void close(CompletionHandler<void()>&&);
 
 private:
     RegistrationDatabase(RegistrationStore&, String&& databaseDirectory);
 
 private:
     RegistrationDatabase(RegistrationStore&, String&& databaseDirectory);
index 69ae4b9..442e62f 100644 (file)
@@ -52,6 +52,11 @@ void RegistrationStore::scheduleDatabasePushIfNecessary()
 
 void RegistrationStore::pushChangesToDatabase(WTF::CompletionHandler<void()>&& completionHandler)
 {
 
 void RegistrationStore::pushChangesToDatabase(WTF::CompletionHandler<void()>&& completionHandler)
 {
+    if (m_isSuspended) {
+        m_needsPushingChanges = true;
+        return;
+    }
+
     Vector<ServiceWorkerContextData> changesToPush;
     changesToPush.reserveInitialCapacity(m_updatedRegistrations.size());
     for (auto& value : m_updatedRegistrations.values())
     Vector<ServiceWorkerContextData> changesToPush;
     changesToPush.reserveInitialCapacity(m_updatedRegistrations.size());
     for (auto& value : m_updatedRegistrations.values())
@@ -63,6 +68,7 @@ void RegistrationStore::pushChangesToDatabase(WTF::CompletionHandler<void()>&& c
 
 void RegistrationStore::clearAll(WTF::CompletionHandler<void()>&& completionHandler)
 {
 
 void RegistrationStore::clearAll(WTF::CompletionHandler<void()>&& completionHandler)
 {
+    m_needsPushingChanges = false;
     m_updatedRegistrations.clear();
     m_databasePushTimer.stop();
     m_database->clearAll(WTFMove(completionHandler));
     m_updatedRegistrations.clear();
     m_databasePushTimer.stop();
     m_database->clearAll(WTFMove(completionHandler));
@@ -78,6 +84,19 @@ void RegistrationStore::flushChanges(WTF::CompletionHandler<void()>&& completion
     completionHandler();
 }
 
     completionHandler();
 }
 
+void RegistrationStore::startSuspension(WTF::CompletionHandler<void()>&& completionHandler)
+{
+    m_isSuspended = true;
+    m_database->close(WTFMove(completionHandler));
+}
+
+void RegistrationStore::endSuspension()
+{
+    m_isSuspended = false;
+    if (m_needsPushingChanges)
+        scheduleDatabasePushIfNecessary();
+}
+
 void RegistrationStore::updateRegistration(const ServiceWorkerContextData& data)
 {
     m_updatedRegistrations.set(data.registration.key, data);
 void RegistrationStore::updateRegistration(const ServiceWorkerContextData& data)
 {
     m_updatedRegistrations.set(data.registration.key, data);
index 0d2dbc2..8dbc319 100644 (file)
@@ -51,6 +51,9 @@ public:
     void clearAll(WTF::CompletionHandler<void()>&&);
     void flushChanges(WTF::CompletionHandler<void()>&&);
 
     void clearAll(WTF::CompletionHandler<void()>&&);
     void flushChanges(WTF::CompletionHandler<void()>&&);
 
+    void startSuspension(WTF::CompletionHandler<void()>&&);
+    void endSuspension();
+
     // Callbacks from the SWServer
     void updateRegistration(const ServiceWorkerContextData&);
     void removeRegistration(SWServerRegistration&);
     // Callbacks from the SWServer
     void updateRegistration(const ServiceWorkerContextData&);
     void removeRegistration(SWServerRegistration&);
@@ -72,6 +75,9 @@ private:
 
     HashMap<ServiceWorkerRegistrationKey, ServiceWorkerContextData> m_updatedRegistrations;
     Timer m_databasePushTimer;
 
     HashMap<ServiceWorkerRegistrationKey, ServiceWorkerContextData> m_updatedRegistrations;
     Timer m_databasePushTimer;
+
+    bool m_isSuspended { false };
+    bool m_needsPushingChanges { false };
 };
 
 } // namespace WebCore
 };
 
 } // namespace WebCore
index 4f670b3..2a283f4 100644 (file)
@@ -210,6 +210,18 @@ void SWServer::clearAll(CompletionHandler<void()>&& completionHandler)
         m_registrationStore->clearAll(WTFMove(completionHandler));
 }
 
         m_registrationStore->clearAll(WTFMove(completionHandler));
 }
 
+void SWServer::startSuspension(CompletionHandler<void()>&& completionHandler)
+{
+    if (m_registrationStore)
+        m_registrationStore->startSuspension(WTFMove(completionHandler));
+}
+
+void SWServer::endSuspension()
+{
+    if (m_registrationStore)
+        m_registrationStore->endSuspension();
+}
+
 void SWServer::clear(const SecurityOriginData& securityOrigin, CompletionHandler<void()>&& completionHandler)
 {
     if (!m_importCompleted) {
 void SWServer::clear(const SecurityOriginData& securityOrigin, CompletionHandler<void()>&& completionHandler)
 {
     if (!m_importCompleted) {
index 0328b74..3ed3da9 100644 (file)
@@ -122,6 +122,9 @@ public:
     WEBCORE_EXPORT void clearAll(WTF::CompletionHandler<void()>&&);
     WEBCORE_EXPORT void clear(const SecurityOriginData&, WTF::CompletionHandler<void()>&&);
 
     WEBCORE_EXPORT void clearAll(WTF::CompletionHandler<void()>&&);
     WEBCORE_EXPORT void clear(const SecurityOriginData&, WTF::CompletionHandler<void()>&&);
 
+    WEBCORE_EXPORT void startSuspension(CompletionHandler<void()>&&);
+    WEBCORE_EXPORT void endSuspension();
+
     SWServerRegistration* getRegistration(const ServiceWorkerRegistrationKey&);
     void addRegistration(std::unique_ptr<SWServerRegistration>&&);
     void removeRegistration(const ServiceWorkerRegistrationKey&);
     SWServerRegistration* getRegistration(const ServiceWorkerRegistrationKey&);
     void addRegistration(std::unique_ptr<SWServerRegistration>&&);
     void removeRegistration(const ServiceWorkerRegistrationKey&);
index 66fcb68..b717e80 100644 (file)
@@ -1,3 +1,28 @@
+2019-04-09  Youenn Fablet  <youenn@apple.com>
+
+        Close service worker database on network process suspension
+        https://bugs.webkit.org/show_bug.cgi?id=196623
+        <rdar://problem/48930869>
+
+        Reviewed by Alex Christensen.
+
+        Close service worker database when preparing to suspend.
+        On resume, push changes if any is needed.
+
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::actualPrepareToSuspend):
+        (WebKit::NetworkProcess::cancelPrepareToSuspend):
+        (WebKit::NetworkProcess::processDidResume):
+        * UIProcess/API/Cocoa/WKProcessPool.mm:
+        (-[WKProcessPool _sendNetworkProcessWillSuspendImminently]):
+        (-[WKProcessPool _sendNetworkProcessDidResume]):
+        * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
+        * UIProcess/Network/NetworkProcessProxy.h:
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::sendNetworkProcessWillSuspendImminently):
+        (WebKit::WebProcessPool::sendNetworkProcessDidResume):
+        * UIProcess/WebProcessPool.h:
+
 2019-04-09  Daniel Bates  <dabates@apple.com>
 
         [iPad] Should open popover when the spacebar is pressed
 2019-04-09  Daniel Bates  <dabates@apple.com>
 
         [iPad] Should open popover when the spacebar is pressed
index fca0972..401bf67 100644 (file)
@@ -1983,6 +1983,9 @@ void NetworkProcess::actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend
 
     for (auto& connection : m_webProcessConnections)
         connection->cleanupForSuspension([delayedTaskCounter] { });
 
     for (auto& connection : m_webProcessConnections)
         connection->cleanupForSuspension([delayedTaskCounter] { });
+
+    for (auto& server : m_swServers.values())
+        server->startSuspension([delayedTaskCounter] { });
 }
 
 void NetworkProcess::processWillSuspendImminently(CompletionHandler<void(bool)>&& completionHandler)
 }
 
 void NetworkProcess::processWillSuspendImminently(CompletionHandler<void(bool)>&& completionHandler)
@@ -2004,9 +2007,7 @@ void NetworkProcess::cancelPrepareToSuspend()
     // message. And NetworkProcessProxy expects to receive either a NetworkProcessProxy::ProcessReadyToSuspend-
     // or NetworkProcessProxy::DidCancelProcessSuspension- message, but not both.
     RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::cancelPrepareToSuspend()", this);
     // message. And NetworkProcessProxy expects to receive either a NetworkProcessProxy::ProcessReadyToSuspend-
     // or NetworkProcessProxy::DidCancelProcessSuspension- message, but not both.
     RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::cancelPrepareToSuspend()", this);
-    platformProcessDidResume();
-    for (auto& connection : m_webProcessConnections)
-        connection->endSuspension();
+    resume();
 }
 
 void NetworkProcess::applicationDidEnterBackground()
 }
 
 void NetworkProcess::applicationDidEnterBackground()
@@ -2022,9 +2023,17 @@ void NetworkProcess::applicationWillEnterForeground()
 void NetworkProcess::processDidResume()
 {
     RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::processDidResume()", this);
 void NetworkProcess::processDidResume()
 {
     RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::processDidResume()", this);
+    resume();
+}
+
+void NetworkProcess::resume()
+{
     platformProcessDidResume();
     for (auto& connection : m_webProcessConnections)
         connection->endSuspension();
     platformProcessDidResume();
     for (auto& connection : m_webProcessConnections)
         connection->endSuspension();
+
+    for (auto& server : m_swServers.values())
+        server->endSuspension();
 }
 
 void NetworkProcess::prefetchDNS(const String& hostname)
 }
 
 void NetworkProcess::prefetchDNS(const String& hostname)
index 7ec329e..7ae4946 100644 (file)
@@ -181,6 +181,7 @@ public:
     void prepareToSuspend();
     void cancelPrepareToSuspend();
     void processDidResume();
     void prepareToSuspend();
     void cancelPrepareToSuspend();
     void processDidResume();
+    void resume();
 
     // Diagnostic messages logging.
     void logDiagnosticMessage(uint64_t webPageID, const String& message, const String& description, WebCore::ShouldSample);
 
     // Diagnostic messages logging.
     void logDiagnosticMessage(uint64_t webPageID, const String& message, const String& description, WebCore::ShouldSample);
index ce1773e..1688a0a 100644 (file)
@@ -425,6 +425,16 @@ static NSDictionary *policiesHashMapToDictionary(const HashMap<String, HashMap<S
     _processPool->terminateNetworkProcess();
 }
 
     _processPool->terminateNetworkProcess();
 }
 
+- (void)_sendNetworkProcessWillSuspendImminently
+{
+    _processPool->sendNetworkProcessWillSuspendImminently();
+}
+
+- (void)_sendNetworkProcessDidResume
+{
+    _processPool->sendNetworkProcessDidResume();
+}
+
 - (void)_terminateServiceWorkerProcesses
 {
     _processPool->terminateServiceWorkerProcesses();
 - (void)_terminateServiceWorkerProcesses
 {
     _processPool->terminateServiceWorkerProcesses();
index f6e0361..0e1f06d 100644 (file)
@@ -83,7 +83,9 @@
 - (_WKDownload *)_resumeDownloadFromData:(NSData *)resumeData path:(NSString *)path originatingWebView:(WKWebView *)webView WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
 // Test only. Should be called only while no web content processes are running.
 - (_WKDownload *)_resumeDownloadFromData:(NSData *)resumeData path:(NSString *)path originatingWebView:(WKWebView *)webView WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
 // Test only. Should be called only while no web content processes are running.
-- (void)_terminateNetworkProcess;
+- (void)_terminateNetworkProcess WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+- (void)_sendNetworkProcessWillSuspendImminently WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+- (void)_sendNetworkProcessDidResume WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)_terminateServiceWorkerProcesses WK_API_AVAILABLE(macos(10.14), ios(12.0));
 - (void)_disableServiceWorkerProcessTerminationDelay WK_API_AVAILABLE(macos(10.14), ios(12.0));
 
 - (void)_terminateServiceWorkerProcesses WK_API_AVAILABLE(macos(10.14), ios(12.0));
 - (void)_disableServiceWorkerProcessTerminationDelay WK_API_AVAILABLE(macos(10.14), ios(12.0));
 
index 47c2299..daceeae 100644 (file)
@@ -183,6 +183,10 @@ public:
     void createSymLinkForFileUpgrade(const String& indexedDatabaseDirectory);
 #endif
 
     void createSymLinkForFileUpgrade(const String& indexedDatabaseDirectory);
 #endif
 
+    // ProcessThrottlerClient
+    void sendProcessWillSuspendImminently() final;
+    void sendProcessDidResume() final;
+
 private:
     // AuxiliaryProcessProxy
     void getLaunchOptions(ProcessLauncher::LaunchOptions&) override;
 private:
     // AuxiliaryProcessProxy
     void getLaunchOptions(ProcessLauncher::LaunchOptions&) override;
@@ -193,11 +197,9 @@ private:
     void clearCallbackStates();
 
     // ProcessThrottlerClient
     void clearCallbackStates();
 
     // ProcessThrottlerClient
-    void sendProcessWillSuspendImminently() override;
-    void sendPrepareToSuspend() override;
-    void sendCancelPrepareToSuspend() override;
-    void sendProcessDidResume() override;
-    void didSetAssertionState(AssertionState) override;
+    void sendPrepareToSuspend() final;
+    void sendCancelPrepareToSuspend() final;
+    void didSetAssertionState(AssertionState) final;
 
     // IPC::Connection::Client
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
 
     // IPC::Connection::Client
     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
index f19d22d..29b4b5a 100644 (file)
@@ -1749,6 +1749,18 @@ void WebProcessPool::terminateNetworkProcess()
     m_didNetworkProcessCrash = true;
 }
 
     m_didNetworkProcessCrash = true;
 }
 
+void WebProcessPool::sendNetworkProcessWillSuspendImminently()
+{
+    if (m_networkProcess)
+        m_networkProcess->sendProcessWillSuspendImminently();
+}
+
+void WebProcessPool::sendNetworkProcessDidResume()
+{
+    if (m_networkProcess)
+        m_networkProcess->sendProcessDidResume();
+}
+
 void WebProcessPool::terminateServiceWorkerProcesses()
 {
 #if ENABLE(SERVICE_WORKER)
 void WebProcessPool::terminateServiceWorkerProcesses()
 {
 #if ENABLE(SERVICE_WORKER)
index 38c8bf1..47834e7 100644 (file)
@@ -295,6 +295,8 @@ public:
 
     void clearCachedCredentials();
     void terminateNetworkProcess();
 
     void clearCachedCredentials();
     void terminateNetworkProcess();
+    void sendNetworkProcessWillSuspendImminently();
+    void sendNetworkProcessDidResume();
     void terminateServiceWorkerProcesses();
     void disableServiceWorkerProcessTerminationDelay();
 
     void terminateServiceWorkerProcesses();
     void disableServiceWorkerProcessTerminationDelay();
 
index 1f10447..1c30a68 100644 (file)
@@ -1,3 +1,13 @@
+2019-04-09  Youenn Fablet  <youenn@apple.com>
+
+        Close service worker database on network process suspension
+        https://bugs.webkit.org/show_bug.cgi?id=196623
+        <rdar://problem/48930869>
+
+        Reviewed by Alex Christensen.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm:
+
 2019-04-09  Daniel Bates  <dabates@apple.com>
 
         [iPad] Should open popover when the spacebar is pressed
 2019-04-09  Daniel Bates  <dabates@apple.com>
 
         [iPad] Should open popover when the spacebar is pressed
index b89f0b6..c0f56f1 100644 (file)
@@ -1734,3 +1734,61 @@ TEST(ServiceWorkers, RestoreFromDiskNonDefaultStore)
         done = false;
     }
 }
         done = false;
     }
 }
+
+TEST(ServiceWorkers, SuspendNetworkProcess)
+{
+    [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
+
+    // Start with a clean slate data store
+    [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+
+    RetainPtr<SWMessageHandler> messageHandler = adoptNS([[SWMessageHandler alloc] init]);
+    [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
+
+    RetainPtr<SWSchemes> handler = adoptNS([[SWSchemes alloc] init]);
+    handler->resources.set("sw://host/main.html", ResourceInfo { @"text/html", mainBytes });
+    handler->resources.set("sw://host/sw.js", ResourceInfo { @"application/javascript", scriptBytes });
+    [configuration setURLSchemeHandler:handler.get() forURLScheme:@"SW"];
+
+    RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+    [webView.get().configuration.processPool _registerURLSchemeServiceWorkersCanHandle:@"sw"];
+
+    auto delegate = adoptNS([[TestSWAsyncNavigationDelegate alloc] init]);
+    [webView setNavigationDelegate:delegate.get()];
+    [webView setUIDelegate:delegate.get()];
+
+    done = false;
+
+    // Normal load to get SW registered.
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"sw://host/main.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto store = [configuration websiteDataStore];
+    auto path = store._serviceWorkerRegistrationDirectory;
+
+    NSURL* directory = [NSURL fileURLWithPath:path isDirectory:YES];
+    NSURL *swDBPath = [directory URLByAppendingPathComponent:@"ServiceWorkerRegistrations-4.sqlite3"];
+
+    EXPECT_TRUE([[NSFileManager defaultManager] fileExistsAtPath:swDBPath.path]);
+
+    [ webView.get().configuration.processPool _sendNetworkProcessWillSuspendImminently];
+
+    EXPECT_TRUE([[NSFileManager defaultManager] fileExistsAtPath:swDBPath.path]);
+
+    [ webView.get().configuration.processPool _sendNetworkProcessDidResume];
+
+    [webView loadRequest:request];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    EXPECT_TRUE([[NSFileManager defaultManager] fileExistsAtPath:swDBPath.path]);
+}