Diff
Modified: trunk/LayoutTests/ChangeLog (225621 => 225622)
--- trunk/LayoutTests/ChangeLog 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/LayoutTests/ChangeLog 2017-12-07 07:37:50 UTC (rev 225622)
@@ -1,3 +1,16 @@
+2017-12-06 Chris Dumez <cdu...@apple.com>
+
+ We should be able to recover after a Service Worker process crash
+ https://bugs.webkit.org/show_bug.cgi?id=180477
+
+ Reviewed by Brady Eidson and Youenn Fablet.
+
+ Add layout test coverage.
+
+ * http/tests/workers/service/postmessage-after-sw-process-crash.https-expected.txt: Added.
+ * http/tests/workers/service/postmessage-after-sw-process-crash.https.html: Added.
+ * http/tests/workers/service/resources/postmessage-after-sw-process-crash.js: Added.
+
2017-12-06 Said Abou-Hallawa <sabouhall...@apple.com>
Support the decoding="sync/async" syntax for image async attribute
Added: trunk/LayoutTests/http/tests/workers/service/postmessage-after-sw-process-crash.https-expected.txt (0 => 225622)
--- trunk/LayoutTests/http/tests/workers/service/postmessage-after-sw-process-crash.https-expected.txt (rev 0)
+++ trunk/LayoutTests/http/tests/workers/service/postmessage-after-sw-process-crash.https-expected.txt 2017-12-07 07:37:50 UTC (rev 225622)
@@ -0,0 +1,8 @@
+* Sending 'Message 1' to Service Worker
+PASS: Client received message from service worker, origin: https://127.0.0.1:8443
+PASS: Service worker received message 'Message 1' from origin 'https://127.0.0.1:8443'
+* Simulating Service Worker process crash
+* Sending 'Message 2' to Service Worker
+PASS: Client received message from service worker, origin: https://127.0.0.1:8443
+PASS: Service worker received message 'Message 2' from origin 'https://127.0.0.1:8443'
+
Added: trunk/LayoutTests/http/tests/workers/service/postmessage-after-sw-process-crash.https.html (0 => 225622)
--- trunk/LayoutTests/http/tests/workers/service/postmessage-after-sw-process-crash.https.html (rev 0)
+++ trunk/LayoutTests/http/tests/workers/service/postmessage-after-sw-process-crash.https.html 2017-12-07 07:37:50 UTC (rev 225622)
@@ -0,0 +1,9 @@
+<html>
+<head>
+<script src=""
+</head>
+<body>
+
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/http/tests/workers/service/resources/postmessage-after-sw-process-crash.js (0 => 225622)
--- trunk/LayoutTests/http/tests/workers/service/resources/postmessage-after-sw-process-crash.js (rev 0)
+++ trunk/LayoutTests/http/tests/workers/service/resources/postmessage-after-sw-process-crash.js 2017-12-07 07:37:50 UTC (rev 225622)
@@ -0,0 +1,28 @@
+var messageNumber = 1;
+navigator.serviceWorker.addEventListener("message", function(event) {
+ log("PASS: Client received message from service worker, origin: " + event.origin);
+ log(event.data);
+ if (messageNumber == 1) {
+ log("* Simulating Service Worker process crash");
+ testRunner.terminateServiceWorkerProcess();
+ setTimeout(function() {
+ log("* Sending 'Message 2' to Service Worker");
+ event.source.postMessage("Message 2");
+ messageNumber++;
+ handle = setTimeout(function() {
+ log("FAIL: Did not receive message from service worker process after the crash");
+ finishSWTest();
+ }, 1000);
+ }, 0);
+ return;
+ }
+ if (messageNumber == 2) {
+ clearTimeout(handle);
+ finishSWTest();
+ }
+});
+
+navigator.serviceWorker.register("resources/postmessage-echo-worker.js", { }).then(function(registration) {
+ log("* Sending 'Message 1' to Service Worker");
+ registration.installing.postMessage("Message 1");
+});
Modified: trunk/Source/WebCore/ChangeLog (225621 => 225622)
--- trunk/Source/WebCore/ChangeLog 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebCore/ChangeLog 2017-12-07 07:37:50 UTC (rev 225622)
@@ -1,3 +1,32 @@
+2017-12-06 Chris Dumez <cdu...@apple.com>
+
+ We should be able to recover after a Service Worker process crash
+ https://bugs.webkit.org/show_bug.cgi?id=180477
+
+ Reviewed by Brady Eidson and Youenn Fablet.
+
+ Test: http/tests/workers/service/postmessage-after-sw-process-crash.https.html
+
+ * workers/service/server/SWServer.cpp:
+ (WebCore::SWServer::serverToContextConnectionCreated):
+ Once the connection with the context process is established, process "run service worker"
+ requests that ocurred while establishing the connection.
+
+ (WebCore::SWServer::runServiceWorkerIfNecessary):
+ Take in a lambda function that gets called after the "run service worker" request
+ is processed. We used to assert that we had a connection to the context process.
+ We now wait for the connection to be established to process the request, thus
+ making the operation asynchronous.
+
+ (WebCore::SWServer::runServiceWorker):
+ Split some logic out of runServiceWorkerIfNecessary() to reuse in serverToContextConnectionCreated().
+
+ (WebCore::SWServer::markAllWorkersAsTerminated):
+ Add method to mark all service workers as terminated. This is called when the Service
+ Worker process crashes.
+
+ * workers/service/server/SWServer.h:
+
2017-12-06 Saam Barati <sbar...@apple.com>
Unreviewed. Fix iOS (and maybe other platform) build
Modified: trunk/Source/WebCore/workers/service/server/SWServer.cpp (225621 => 225622)
--- trunk/Source/WebCore/workers/service/server/SWServer.cpp 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebCore/workers/service/server/SWServer.cpp 2017-12-07 07:37:50 UTC (rev 225622)
@@ -421,11 +421,19 @@
void SWServer::serverToContextConnectionCreated()
{
- ASSERT(SWServerToContextConnection::globalServerToContextConnection());
- for (auto& data : m_pendingContextDatas)
+ auto* connection = SWServerToContextConnection::globalServerToContextConnection();
+ ASSERT(connection);
+
+ auto pendingContextDatas = WTFMove(m_pendingContextDatas);
+ for (auto& data : pendingContextDatas)
installContextData(data);
-
- m_pendingContextDatas.clear();
+
+ auto serviceWorkerRunRequests = WTFMove(m_serviceWorkerRunRequests);
+ for (auto& item : serviceWorkerRunRequests) {
+ bool success = runServiceWorker(item.key);
+ for (auto& callback : item.value)
+ callback(success, *connection);
+ }
}
void SWServer::installContextData(const ServiceWorkerContextData& data)
@@ -446,16 +454,32 @@
connection->installServiceWorkerContext(data);
}
-bool SWServer::invokeRunServiceWorker(ServiceWorkerIdentifier identifier)
+void SWServer::runServiceWorkerIfNecessary(ServiceWorkerIdentifier identifier, RunServiceWorkerCallback&& callback)
{
+ auto* connection = SWServerToContextConnection::globalServerToContextConnection();
if (auto* worker = m_runningOrTerminatingWorkers.get(identifier)) {
- if (worker->isRunning())
- return true;
+ if (worker->isRunning()) {
+ ASSERT(connection);
+ callback(true, *connection);
+ return;
+ }
}
- // Nobody should have a ServiceWorkerIdentifier for a SWServerWorker that doesn't exist.
+ if (!connection) {
+ m_serviceWorkerRunRequests.ensure(identifier, [&] {
+ return Vector<RunServiceWorkerCallback> { };
+ }).iterator->value.append(WTFMove(callback));
+ return;
+ }
+
+ callback(runServiceWorker(identifier), *connection);
+}
+
+bool SWServer::runServiceWorker(ServiceWorkerIdentifier identifier)
+{
auto* worker = workerByID(identifier);
- ASSERT(worker);
+ if (!worker)
+ return false;
// If the registration for a working has been removed then the request to run
// the worker is moot.
@@ -462,13 +486,15 @@
if (!getRegistration(worker->registrationKey()))
return false;
- m_runningOrTerminatingWorkers.add(identifier, *worker);
+ auto addResult = m_runningOrTerminatingWorkers.add(identifier, *worker);
+ ASSERT_UNUSED(addResult, addResult.isNewEntry);
+
worker->setState(SWServerWorker::State::Running);
auto* connection = SWServerToContextConnection::globalServerToContextConnection();
ASSERT(connection);
connection->installServiceWorkerContext(worker->contextData());
-
+
return true;
}
@@ -505,10 +531,14 @@
};
}
+void SWServer::markAllWorkersAsTerminated()
+{
+ while (!m_runningOrTerminatingWorkers.isEmpty())
+ workerContextTerminated(m_runningOrTerminatingWorkers.begin()->value);
+}
+
void SWServer::workerContextTerminated(SWServerWorker& worker)
{
- ASSERT(worker.isTerminating());
-
worker.setState(SWServerWorker::State::NotRunning);
// At this point if no registrations are referencing the worker then it will be destroyed,
Modified: trunk/Source/WebCore/workers/service/server/SWServer.h (225621 => 225622)
--- trunk/Source/WebCore/workers/service/server/SWServer.h 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebCore/workers/service/server/SWServer.h 2017-12-07 07:37:50 UTC (rev 225622)
@@ -140,6 +140,8 @@
void fireInstallEvent(SWServerWorker&);
void fireActivateEvent(SWServerWorker&);
WEBCORE_EXPORT SWServerWorker* workerByID(ServiceWorkerIdentifier) const;
+
+ WEBCORE_EXPORT void markAllWorkersAsTerminated();
Connection* getConnection(SWServerConnectionIdentifier identifier) { return m_connections.get(identifier); }
SWOriginStore& originStore() { return m_originStore; }
@@ -160,7 +162,8 @@
WEBCORE_EXPORT void registerServiceWorkerClient(ClientOrigin&&, ServiceWorkerClientIdentifier, ServiceWorkerClientData&&, const std::optional<ServiceWorkerIdentifier>& controllingServiceWorkerIdentifier);
WEBCORE_EXPORT void unregisterServiceWorkerClient(const ClientOrigin&, ServiceWorkerClientIdentifier);
- WEBCORE_EXPORT bool invokeRunServiceWorker(ServiceWorkerIdentifier);
+ using RunServiceWorkerCallback = WTF::Function<void(bool, SWServerToContextConnection&)>;
+ WEBCORE_EXPORT void runServiceWorkerIfNecessary(ServiceWorkerIdentifier, RunServiceWorkerCallback&&);
void setClientActiveWorker(ServiceWorkerClientIdentifier, ServiceWorkerIdentifier);
void resolveRegistrationReadyRequests(SWServerRegistration&);
@@ -180,6 +183,7 @@
void removeClientServiceWorkerRegistration(Connection&, ServiceWorkerRegistrationIdentifier);
WEBCORE_EXPORT SWServerRegistration* doRegistrationMatching(const SecurityOriginData& topOrigin, const URL& clientURL);
+ bool runServiceWorker(ServiceWorkerIdentifier);
void installContextData(const ServiceWorkerContextData&);
@@ -216,6 +220,7 @@
UniqueRef<SWOriginStore> m_originStore;
RegistrationStore m_registrationStore;
Deque<ServiceWorkerContextData> m_pendingContextDatas;
+ HashMap<ServiceWorkerIdentifier, Vector<RunServiceWorkerCallback>> m_serviceWorkerRunRequests;
};
} // namespace WebCore
Modified: trunk/Source/WebKit/ChangeLog (225621 => 225622)
--- trunk/Source/WebKit/ChangeLog 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/ChangeLog 2017-12-07 07:37:50 UTC (rev 225622)
@@ -1,3 +1,59 @@
+2017-12-06 Chris Dumez <cdu...@apple.com>
+
+ We should be able to recover after a Service Worker process crash
+ https://bugs.webkit.org/show_bug.cgi?id=180477
+
+ Reviewed by Brady Eidson and Youenn Fablet.
+
+ * StorageProcess/ServiceWorker/WebSWServerConnection.cpp:
+ (WebKit::WebSWServerConnection::startFetch):
+ (WebKit::WebSWServerConnection::postMessageToServiceWorkerFromClient):
+ (WebKit::WebSWServerConnection::postMessageToServiceWorkerFromServiceWorker):
+ Update calls to SWServer::runServiceWorkerIfNecessary() that that it is asynchronous
+ and takes in a lambda.
+
+ * StorageProcess/ServiceWorker/WebSWServerConnection.h:
+ (WebKit::WebSWServerConnection::ipcConnection const):
+ Add getter for the underlying IPC connection.
+
+ * StorageProcess/StorageProcess.cpp:
+ (WebKit::StorageProcess::didClose):
+ (WebKit::StorageProcess::connectionToContextProcessWasClosed):
+ Move some code to connectionToContextProcessWasClosed() to avoid duplication.
+ Also, relaunch the Service Worker process if it has exited but we still
+ have SWServer connections to regular Web Processes.
+
+ (WebKit::StorageProcess::needsServerToContextConnection const):
+ Utility function to determine if we still need the service worker process.
+ The current rule is that we need the service worker (aka "context") process
+ if we still have SWServer connections to regular Web Processes.
+
+ * StorageProcess/StorageProcess.h:
+
+ * StorageProcess/StorageToWebProcessConnection.cpp:
+ (WebKit::StorageToWebProcessConnection::didClose):
+ If didClose() is called for the connection to the service worker context,
+ let the StorageProcess know so that it can clear its state and relaunch
+ the process if necessary.
+
+ * UIProcess/API/C/WKContext.cpp:
+ (WKContextTerminateServiceWorkerProcess):
+ * UIProcess/API/C/WKContextPrivate.h:
+ * UIProcess/API/Cocoa/WKProcessPool.mm:
+ (-[WKProcessPool _terminateServiceWorkerProcess]):
+ * UIProcess/API/Cocoa/WKProcessPoolPrivate.h:
+ Add SPI to terminate the service worker process.
+
+ * UIProcess/WebProcessPool.cpp:
+ (WebKit::m_serviceWorkerProcessTerminationTimer):
+ (WebKit::WebProcessPool::createNewWebProcess):
+ (WebKit::WebProcessPool::disconnectProcess):
+ (WebKit::WebProcessPool::terminateServiceWorkerProcess):
+ * UIProcess/WebProcessPool.h:
+ We used to shutdown the ServiceWorker process right away as soon as the last regular
+ WebProcess was gone. We now give it a grace period of 5 seconds in case a new
+ WebProcess gets launched shortly after.
+
2017-12-02 Darin Adler <da...@apple.com>
Modernize some aspects of text codecs, eliminate WebKit use of strcasecmp
Modified: trunk/Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.cpp (225621 => 225622)
--- trunk/Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.cpp 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.cpp 2017-12-07 07:37:50 UTC (rev 225622)
@@ -116,11 +116,18 @@
send(Messages::WebSWClientConnection::UpdateWorkerState(worker, state));
}
-void WebSWServerConnection::startFetch(uint64_t fetchIdentifier, std::optional<ServiceWorkerIdentifier> serviceWorkerIdentifier, const ResourceRequest& request, const FetchOptions& options, const IPC::FormDataReference& formData)
+void WebSWServerConnection::startFetch(uint64_t fetchIdentifier, std::optional<ServiceWorkerIdentifier> serviceWorkerIdentifier, ResourceRequest&& request, FetchOptions&& options, IPC::FormDataReference&& formData)
{
// It's possible this specific worker cannot be re-run (e.g. its registration has been removed)
- if (serviceWorkerIdentifier && !server().invokeRunServiceWorker(*serviceWorkerIdentifier))
+ if (serviceWorkerIdentifier) {
+ server().runServiceWorkerIfNecessary(*serviceWorkerIdentifier, [contentConnection = m_contentConnection.copyRef(), connectionIdentifier = identifier(), fetchIdentifier, serviceWorkerIdentifier = *serviceWorkerIdentifier, request = WTFMove(request), options = WTFMove(options), formData = WTFMove(formData)](bool success, auto& contextConnection) {
+ if (success)
+ sendToContextProcess(contextConnection, Messages::WebSWContextManagerConnection::StartFetch { connectionIdentifier, fetchIdentifier, serviceWorkerIdentifier, request, options, formData });
+ else
+ contentConnection->send(Messages::ServiceWorkerClientFetch::DidNotHandle { }, fetchIdentifier);
+ });
return;
+ }
// FIXME: If we don't have a ServiceWorkerIdentifier here then we need to create and run the appropriate Service Worker,
// but it's unclear that we have enough information here to do that.
@@ -128,26 +135,28 @@
sendToContextProcess(Messages::WebSWContextManagerConnection::StartFetch { identifier(), fetchIdentifier, serviceWorkerIdentifier, request, options, formData });
}
-void WebSWServerConnection::postMessageToServiceWorkerFromClient(ServiceWorkerIdentifier destinationIdentifier, const IPC::DataReference& message, ServiceWorkerClientIdentifier sourceIdentifier, ServiceWorkerClientData&& sourceData)
+void WebSWServerConnection::postMessageToServiceWorkerFromClient(ServiceWorkerIdentifier destinationIdentifier, IPC::DataReference&& message, ServiceWorkerClientIdentifier sourceIdentifier, ServiceWorkerClientData&& sourceData)
{
// It's possible this specific worker cannot be re-run (e.g. its registration has been removed)
- if (!server().invokeRunServiceWorker(destinationIdentifier))
- return;
-
- sendToContextProcess(Messages::WebSWContextManagerConnection::PostMessageToServiceWorkerFromClient { destinationIdentifier, message, sourceIdentifier, WTFMove(sourceData) });
+ server().runServiceWorkerIfNecessary(destinationIdentifier, [destinationIdentifier, message = WTFMove(message), sourceIdentifier, sourceData = WTFMove(sourceData)](bool success, auto& contextConnection) mutable {
+ if (success)
+ sendToContextProcess(contextConnection, Messages::WebSWContextManagerConnection::PostMessageToServiceWorkerFromClient { destinationIdentifier, message, sourceIdentifier, WTFMove(sourceData) });
+ });
}
-void WebSWServerConnection::postMessageToServiceWorkerFromServiceWorker(ServiceWorkerIdentifier destinationIdentifier, const IPC::DataReference& message, ServiceWorkerIdentifier sourceIdentifier)
+void WebSWServerConnection::postMessageToServiceWorkerFromServiceWorker(ServiceWorkerIdentifier destinationIdentifier, IPC::DataReference&& message, ServiceWorkerIdentifier sourceIdentifier)
{
- // It's possible this specific worker cannot be re-run (e.g. its registration has been removed)
- if (!server().invokeRunServiceWorker(destinationIdentifier))
- return;
-
auto* sourceWorker = server().workerByID(sourceIdentifier);
if (!sourceWorker)
return;
- sendToContextProcess(Messages::WebSWContextManagerConnection::PostMessageToServiceWorkerFromServiceWorker { destinationIdentifier, message, sourceWorker->data() });
+ // It's possible this specific worker cannot be re-run (e.g. its registration has been removed)
+ server().runServiceWorkerIfNecessary(destinationIdentifier, [destinationIdentifier, message = WTFMove(message), sourceIdentifier, sourceData = sourceWorker->data()](bool success, auto& contextConnection) mutable {
+ if (!success)
+ return;
+
+ sendToContextProcess(contextConnection, Messages::WebSWContextManagerConnection::PostMessageToServiceWorkerFromServiceWorker { destinationIdentifier, message, WTFMove(sourceData) });
+ });
}
void WebSWServerConnection::didReceiveFetchResponse(uint64_t fetchIdentifier, const ResourceResponse& response)
@@ -232,6 +241,11 @@
connection->send(WTFMove(message));
}
+template<typename U> void WebSWServerConnection::sendToContextProcess(WebCore::SWServerToContextConnection& connection, U&& message)
+{
+ static_cast<WebSWServerToContextConnection&>(connection).send(WTFMove(message));
+}
+
} // namespace WebKit
#endif // ENABLE(SERVICE_WORKER)
Modified: trunk/Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.h (225621 => 225622)
--- trunk/Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.h 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/StorageProcess/ServiceWorker/WebSWServerConnection.h 2017-12-07 07:37:50 UTC (rev 225622)
@@ -52,6 +52,8 @@
WebSWServerConnection(const WebSWServerConnection&) = delete;
~WebSWServerConnection() final;
+ IPC::Connection& ipcConnection() const { return m_contentConnection.get(); }
+
void disconnectedFromWebProcess();
void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;
void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&);
@@ -79,10 +81,10 @@
void notifyClientsOfControllerChange(const HashSet<WebCore::DocumentIdentifier>& contextIdentifiers, const WebCore::ServiceWorkerData& newController);
void registrationReady(uint64_t registrationReadyRequestIdentifier, WebCore::ServiceWorkerRegistrationData&&) final;
- void startFetch(uint64_t fetchIdentifier, std::optional<WebCore::ServiceWorkerIdentifier>, const WebCore::ResourceRequest&, const WebCore::FetchOptions&, const IPC::FormDataReference&);
+ void startFetch(uint64_t fetchIdentifier, std::optional<WebCore::ServiceWorkerIdentifier>, WebCore::ResourceRequest&&, WebCore::FetchOptions&&, IPC::FormDataReference&&);
- void postMessageToServiceWorkerFromClient(WebCore::ServiceWorkerIdentifier destination, const IPC::DataReference& message, WebCore::ServiceWorkerClientIdentifier sourceIdentifier, WebCore::ServiceWorkerClientData&& source);
- void postMessageToServiceWorkerFromServiceWorker(WebCore::ServiceWorkerIdentifier destination, const IPC::DataReference& message, WebCore::ServiceWorkerIdentifier source);
+ void postMessageToServiceWorkerFromClient(WebCore::ServiceWorkerIdentifier destination, IPC::DataReference&& message, WebCore::ServiceWorkerClientIdentifier sourceIdentifier, WebCore::ServiceWorkerClientData&& source);
+ void postMessageToServiceWorkerFromServiceWorker(WebCore::ServiceWorkerIdentifier destination, IPC::DataReference&& message, WebCore::ServiceWorkerIdentifier source);
void matchRegistration(uint64_t registrationMatchRequestIdentifier, const WebCore::SecurityOriginData& topOrigin, const WebCore::URL& clientURL);
void getRegistrations(uint64_t registrationMatchRequestIdentifier, const WebCore::SecurityOriginData& topOrigin, const WebCore::URL& clientURL);
@@ -94,10 +96,10 @@
uint64_t messageSenderDestinationID() final { return identifier().toUInt64(); }
template<typename U> void sendToContextProcess(U&& message);
+ template<typename U> static void sendToContextProcess(WebCore::SWServerToContextConnection&, U&& message);
PAL::SessionID m_sessionID;
Ref<IPC::Connection> m_contentConnection;
- RefPtr<IPC::Connection> m_contextConnection;
HashMap<WebCore::DocumentIdentifier, WebCore::ClientOrigin> m_clientOrigins;
};
Modified: trunk/Source/WebKit/StorageProcess/StorageProcess.cpp (225621 => 225622)
--- trunk/Source/WebKit/StorageProcess/StorageProcess.cpp 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/StorageProcess/StorageProcess.cpp 2017-12-07 07:37:50 UTC (rev 225622)
@@ -86,8 +86,7 @@
{
#if ENABLE(SERVICE_WORKER)
if (m_serverToContextConnection && m_serverToContextConnection->ipcConnection() == &connection) {
- m_serverToContextConnection->connectionClosed();
- m_serverToContextConnection = nullptr;
+ connectionToContextProcessWasClosed();
return;
}
#else
@@ -96,6 +95,38 @@
stopRunLoop();
}
+#if ENABLE(SERVICE_WORKER)
+void StorageProcess::connectionToContextProcessWasClosed()
+{
+ if (!m_serverToContextConnection)
+ return;
+
+ bool shouldRelaunch = needsServerToContextConnection();
+
+ m_serverToContextConnection->connectionClosed();
+ m_serverToContextConnection = nullptr;
+
+ for (auto& swServer : m_swServers.values())
+ swServer->markAllWorkersAsTerminated();
+
+ if (shouldRelaunch)
+ createServerToContextConnection();
+}
+
+// The rule is that we need a context process (and a connection to it) as long as we have SWServerConnections to regular WebProcesses.
+bool StorageProcess::needsServerToContextConnection() const
+{
+ if (m_swServerConnections.isEmpty())
+ return false;
+
+ // If the last SWServerConnection is to the context process, then we no longer need the context connection.
+ if (m_swServerConnections.size() == 1 && m_serverToContextConnection && &m_swServerConnections.begin()->value->ipcConnection() == m_serverToContextConnection->ipcConnection())
+ return false;
+
+ return true;
+}
+#endif
+
void StorageProcess::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
{
if (messageReceiverMap().dispatchMessage(connection, decoder))
Modified: trunk/Source/WebKit/StorageProcess/StorageProcess.h (225621 => 225622)
--- trunk/Source/WebKit/StorageProcess/StorageProcess.h 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/StorageProcess/StorageProcess.h 2017-12-07 07:37:50 UTC (rev 225622)
@@ -98,6 +98,10 @@
void didReceiveStorageProcessMessage(IPC::Connection&, IPC::Decoder&);
+#if ENABLE(SERVICE_WORKER)
+ void connectionToContextProcessWasClosed();
+#endif
+
private:
StorageProcess();
@@ -133,6 +137,7 @@
void postMessageToServiceWorkerClient(const WebCore::ServiceWorkerClientIdentifier& destinationIdentifier, const IPC::DataReference& message, WebCore::ServiceWorkerIdentifier sourceIdentifier, const String& sourceOrigin);
WebSWOriginStore& swOriginStoreForSession(PAL::SessionID);
+ bool needsServerToContextConnection() const;
#endif
#if ENABLE(INDEXED_DATABASE)
Vector<WebCore::SecurityOriginData> indexedDatabaseOrigins(const String& path);
Modified: trunk/Source/WebKit/StorageProcess/StorageToWebProcessConnection.cpp (225621 => 225622)
--- trunk/Source/WebKit/StorageProcess/StorageToWebProcessConnection.cpp 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/StorageProcess/StorageToWebProcessConnection.cpp 2017-12-07 07:37:50 UTC (rev 225622)
@@ -120,8 +120,17 @@
ASSERT_NOT_REACHED();
}
-void StorageToWebProcessConnection::didClose(IPC::Connection&)
+void StorageToWebProcessConnection::didClose(IPC::Connection& connection)
{
+ UNUSED_PARAM(connection);
+
+#if ENABLE(SERVICE_WORKER)
+ if (StorageProcess::singleton().globalServerToContextConnection() && StorageProcess::singleton().globalServerToContextConnection()->ipcConnection() == &connection) {
+ // Service Worker process exited.
+ StorageProcess::singleton().connectionToContextProcessWasClosed();
+ }
+#endif
+
#if ENABLE(INDEXED_DATABASE)
auto idbConnections = m_webIDBConnections;
for (auto& connection : idbConnections.values())
Modified: trunk/Source/WebKit/UIProcess/API/C/WKContext.cpp (225621 => 225622)
--- trunk/Source/WebKit/UIProcess/API/C/WKContext.cpp 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/UIProcess/API/C/WKContext.cpp 2017-12-07 07:37:50 UTC (rev 225622)
@@ -614,6 +614,11 @@
toImpl(context)->terminateNetworkProcess();
}
+void WKContextTerminateServiceWorkerProcess(WKContextRef context)
+{
+ toImpl(context)->terminateServiceWorkerProcess();
+}
+
ProcessID WKContextGetNetworkProcessIdentifier(WKContextRef contextRef)
{
return toImpl(contextRef)->networkProcessIdentifier();
Modified: trunk/Source/WebKit/UIProcess/API/C/WKContextPrivate.h (225621 => 225622)
--- trunk/Source/WebKit/UIProcess/API/C/WKContextPrivate.h 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/UIProcess/API/C/WKContextPrivate.h 2017-12-07 07:37:50 UTC (rev 225622)
@@ -89,6 +89,7 @@
WK_EXPORT void WKContextSetUsesNetworkProcess(WKContextRef, bool);
WK_EXPORT void WKContextTerminateNetworkProcess(WKContextRef);
+WK_EXPORT void WKContextTerminateServiceWorkerProcess(WKContextRef);
WK_EXPORT void WKContextSetAllowsAnySSLCertificateForWebSocketTesting(WKContextRef, bool);
WK_EXPORT void WKContextSetAllowsAnySSLCertificateForServiceWorkerTesting(WKContextRef, bool);
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm (225621 => 225622)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm 2017-12-07 07:37:50 UTC (rev 225622)
@@ -412,6 +412,11 @@
_processPool->terminateNetworkProcess();
}
+- (void)_terminateServiceWorkerProcess
+{
+ _processPool->terminateServiceWorkerProcess();
+}
+
- (pid_t)_networkProcessIdentifier
{
return _processPool->networkProcessIdentifier();
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h (225621 => 225622)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h 2017-12-07 07:37:50 UTC (rev 225622)
@@ -74,6 +74,7 @@
// Test only. Should be called only while no web content processes are running.
- (void)_terminateStorageProcess;
- (void)_terminateNetworkProcess;
+- (void)_terminateServiceWorkerProcess;
// Test only.
- (pid_t)_networkProcessIdentifier WK_API_AVAILABLE(macosx(10.13), ios(11.0));
Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (225621 => 225622)
--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp 2017-12-07 07:37:50 UTC (rev 225622)
@@ -115,6 +115,8 @@
DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, processPoolCounter, ("WebProcessPool"));
+static const Seconds serviceWorkerTerminationDelay { 5_s };
+
static uint64_t generateListenerIdentifier()
{
static uint64_t nextIdentifier = 1;
@@ -244,6 +246,7 @@
, m_processSuppressionDisabledForPageCounter([this](RefCounterEvent) { updateProcessSuppressionState(); })
, m_hiddenPageThrottlingAutoIncreasesCounter([this](RefCounterEvent) { m_hiddenPageThrottlingTimer.startOneShot(0_s); })
, m_hiddenPageThrottlingTimer(RunLoop::main(), this, &WebProcessPool::updateHiddenPageThrottlingAutoIncreaseLimit)
+ , m_serviceWorkerProcessTerminationTimer(RunLoop::main(), this, &WebProcessPool::terminateServiceWorkerProcess)
{
if (m_configuration->shouldHaveLegacyDataStore())
m_websiteDataStore = API::WebsiteDataStore::createLegacy(legacyWebsiteDataStoreConfiguration(m_configuration));
@@ -697,6 +700,10 @@
auto& process = processProxy.get();
initializeNewWebProcess(process, websiteDataStore);
m_processes.append(WTFMove(processProxy));
+
+ if (m_serviceWorkerProcessTerminationTimer.isActive())
+ m_serviceWorkerProcessTerminationTimer.stop();
+
return process;
}
@@ -943,8 +950,8 @@
// FIXME: We should do better than this. For now, we just destroy the ServiceWorker process
// whenever there is no regular WebContent process remaining.
if (m_processes.size() == 1 && m_processes[0] == m_serviceWorkerProcess) {
- m_serviceWorkerProcess = nullptr;
- m_processes.clear();
+ if (!m_serviceWorkerProcessTerminationTimer.isActive())
+ m_serviceWorkerProcessTerminationTimer.startOneShot(serviceWorkerTerminationDelay);
}
#endif
}
@@ -1408,6 +1415,18 @@
m_didNetworkProcessCrash = true;
}
+void WebProcessPool::terminateServiceWorkerProcess()
+{
+#if ENABLE(SERVICE_WORKER)
+ if (!m_serviceWorkerProcess)
+ return;
+
+ m_serviceWorkerProcess->requestTermination(ProcessTerminationReason::RequestedByClient);
+ ASSERT(!m_processes.contains(m_serviceWorkerProcess));
+ ASSERT(!m_serviceWorkerProcess);
+#endif
+}
+
void WebProcessPool::syncNetworkProcessCookies()
{
sendSyncToNetworkingProcess(Messages::NetworkProcess::SyncAllCookies(), Messages::NetworkProcess::SyncAllCookies::Reply());
Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (225621 => 225622)
--- trunk/Source/WebKit/UIProcess/WebProcessPool.h 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.h 2017-12-07 07:37:50 UTC (rev 225622)
@@ -262,6 +262,7 @@
void clearCachedCredentials();
void terminateStorageProcess();
void terminateNetworkProcess();
+ void terminateServiceWorkerProcess();
void syncNetworkProcessCookies();
@@ -633,6 +634,7 @@
Paths m_resolvedPaths;
HashMap<PAL::SessionID, HashSet<WebPageProxy*>> m_sessionToPagesMap;
+ RunLoop::Timer<WebProcessPool> m_serviceWorkerProcessTerminationTimer;
};
template<typename T>
Modified: trunk/Tools/ChangeLog (225621 => 225622)
--- trunk/Tools/ChangeLog 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Tools/ChangeLog 2017-12-07 07:37:50 UTC (rev 225622)
@@ -1,3 +1,22 @@
+2017-12-06 Chris Dumez <cdu...@apple.com>
+
+ We should be able to recover after a Service Worker process crash
+ https://bugs.webkit.org/show_bug.cgi?id=180477
+
+ Reviewed by Brady Eidson and Youenn Fablet.
+
+ Add testRunner API to terminate the Service Worker process.
+
+ * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl:
+ * WebKitTestRunner/InjectedBundle/TestRunner.cpp:
+ (WTR::TestRunner::terminateServiceWorkerProcess):
+ * WebKitTestRunner/InjectedBundle/TestRunner.h:
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::terminateServiceWorkerProcess):
+ * WebKitTestRunner/TestController.h:
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::didReceiveMessageFromInjectedBundle):
+
2017-12-02 Darin Adler <da...@apple.com>
Modernize some aspects of text codecs, eliminate WebKit use of strcasecmp
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl (225621 => 225622)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl 2017-12-07 07:37:50 UTC (rev 225622)
@@ -304,6 +304,7 @@
void setWebRTCLegacyAPIEnabled(boolean value);
void terminateNetworkProcess();
+ void terminateServiceWorkerProcess();
void removeAllSessionCredentials(object callback);
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp (225621 => 225622)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp 2017-12-07 07:37:50 UTC (rev 225622)
@@ -1138,6 +1138,12 @@
WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr);
}
+void TestRunner::terminateServiceWorkerProcess()
+{
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("TerminateServiceWorkerProcess"));
+ WKBundlePagePostMessage(InjectedBundle::singleton().page()->page(), messageName.get(), nullptr);
+}
+
static unsigned nextUIScriptCallbackID()
{
static unsigned callbackID = FirstUIScriptCallbackID;
Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h (225621 => 225622)
--- trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h 2017-12-07 07:37:50 UTC (rev 225622)
@@ -402,6 +402,7 @@
void setOpenPanelFiles(JSValueRef);
void terminateNetworkProcess();
+ void terminateServiceWorkerProcess();
void removeAllSessionCredentials(JSValueRef);
void callDidRemoveAllSessionCredentialsCallback();
Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (225621 => 225622)
--- trunk/Tools/WebKitTestRunner/TestController.cpp 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp 2017-12-07 07:37:50 UTC (rev 225622)
@@ -2274,6 +2274,11 @@
WKContextTerminateNetworkProcess(platformContext());
}
+void TestController::terminateServiceWorkerProcess()
+{
+ WKContextTerminateServiceWorkerProcess(platformContext());
+}
+
#if !PLATFORM(COCOA)
void TestController::platformWillRunTest(const TestInvocation&)
{
Modified: trunk/Tools/WebKitTestRunner/TestController.h (225621 => 225622)
--- trunk/Tools/WebKitTestRunner/TestController.h 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Tools/WebKitTestRunner/TestController.h 2017-12-07 07:37:50 UTC (rev 225622)
@@ -188,6 +188,7 @@
void setOpenPanelFileURLs(WKArrayRef fileURLs) { m_openPanelFileURLs = fileURLs; }
void terminateNetworkProcess();
+ void terminateServiceWorkerProcess();
void removeAllSessionCredentials();
Modified: trunk/Tools/WebKitTestRunner/TestInvocation.cpp (225621 => 225622)
--- trunk/Tools/WebKitTestRunner/TestInvocation.cpp 2017-12-07 06:47:16 UTC (rev 225621)
+++ trunk/Tools/WebKitTestRunner/TestInvocation.cpp 2017-12-07 07:37:50 UTC (rev 225622)
@@ -744,6 +744,12 @@
return;
}
+ if (WKStringIsEqualToUTF8CString(messageName, "TerminateServiceWorkerProcess")) {
+ ASSERT(!messageBody);
+ TestController::singleton().terminateServiceWorkerProcess();
+ return;
+ }
+
if (WKStringIsEqualToUTF8CString(messageName, "RunUIProcessScript")) {
WKDictionaryRef messageBodyDictionary = static_cast<WKDictionaryRef>(messageBody);
WKRetainPtr<WKStringRef> scriptKey(AdoptWK, WKStringCreateWithUTF8CString("Script"));