1 | /* |
2 | * Copyright (C) 2017 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "SWContextManager.h" |
28 | |
29 | #if ENABLE(SERVICE_WORKER) |
30 | #include "Logging.h" |
31 | #include "MessageWithMessagePorts.h" |
32 | #include "ServiceWorkerClientIdentifier.h" |
33 | #include "ServiceWorkerGlobalScope.h" |
34 | |
35 | namespace WebCore { |
36 | |
37 | SWContextManager& SWContextManager::singleton() |
38 | { |
39 | static SWContextManager* sharedManager = new SWContextManager; |
40 | return *sharedManager; |
41 | } |
42 | |
43 | void SWContextManager::setConnection(std::unique_ptr<Connection>&& connection) |
44 | { |
45 | ASSERT(!m_connection); |
46 | m_connection = WTFMove(connection); |
47 | } |
48 | |
49 | auto SWContextManager::connection() const -> Connection* |
50 | { |
51 | return m_connection.get(); |
52 | } |
53 | |
54 | void SWContextManager::registerServiceWorkerThreadForInstall(Ref<ServiceWorkerThreadProxy>&& serviceWorkerThreadProxy) |
55 | { |
56 | auto serviceWorkerIdentifier = serviceWorkerThreadProxy->identifier(); |
57 | auto jobDataIdentifier = serviceWorkerThreadProxy->thread().contextData().jobDataIdentifier; |
58 | auto* threadProxy = serviceWorkerThreadProxy.ptr(); |
59 | auto result = m_workerMap.add(serviceWorkerIdentifier, WTFMove(serviceWorkerThreadProxy)); |
60 | ASSERT_UNUSED(result, result.isNewEntry); |
61 | |
62 | threadProxy->thread().start([jobDataIdentifier, serviceWorkerIdentifier](const String& exceptionMessage) { |
63 | SWContextManager::singleton().startedServiceWorker(jobDataIdentifier, serviceWorkerIdentifier, exceptionMessage); |
64 | }); |
65 | } |
66 | |
67 | void SWContextManager::startedServiceWorker(Optional<ServiceWorkerJobDataIdentifier> jobDataIdentifier, ServiceWorkerIdentifier serviceWorkerIdentifier, const String& exceptionMessage) |
68 | { |
69 | connection()->serviceWorkerStartedWithMessage(jobDataIdentifier, serviceWorkerIdentifier, exceptionMessage); |
70 | if (m_serviceWorkerCreationCallback) |
71 | m_serviceWorkerCreationCallback(serviceWorkerIdentifier.toUInt64()); |
72 | } |
73 | |
74 | ServiceWorkerThreadProxy* SWContextManager::serviceWorkerThreadProxy(ServiceWorkerIdentifier identifier) const |
75 | { |
76 | return m_workerMap.get(identifier); |
77 | } |
78 | |
79 | void SWContextManager::postMessageToServiceWorker(ServiceWorkerIdentifier destination, MessageWithMessagePorts&& message, ServiceWorkerOrClientData&& sourceData) |
80 | { |
81 | auto* serviceWorker = m_workerMap.get(destination); |
82 | ASSERT(serviceWorker); |
83 | ASSERT(!serviceWorker->isTerminatingOrTerminated()); |
84 | |
85 | // FIXME: We should pass valid MessagePortChannels. |
86 | serviceWorker->thread().postMessageToServiceWorker(WTFMove(message), WTFMove(sourceData)); |
87 | } |
88 | |
89 | void SWContextManager::fireInstallEvent(ServiceWorkerIdentifier identifier) |
90 | { |
91 | auto* serviceWorker = m_workerMap.get(identifier); |
92 | if (!serviceWorker) |
93 | return; |
94 | |
95 | serviceWorker->thread().fireInstallEvent(); |
96 | } |
97 | |
98 | void SWContextManager::fireActivateEvent(ServiceWorkerIdentifier identifier) |
99 | { |
100 | auto* serviceWorker = m_workerMap.get(identifier); |
101 | if (!serviceWorker) |
102 | return; |
103 | |
104 | serviceWorker->thread().fireActivateEvent(); |
105 | } |
106 | |
107 | void SWContextManager::terminateWorker(ServiceWorkerIdentifier identifier, Seconds timeout, Function<void()>&& completionHandler) |
108 | { |
109 | auto serviceWorker = m_workerMap.take(identifier); |
110 | if (!serviceWorker) { |
111 | if (completionHandler) |
112 | completionHandler(); |
113 | return; |
114 | } |
115 | |
116 | serviceWorker->setAsTerminatingOrTerminated(); |
117 | |
118 | m_pendingServiceWorkerTerminationRequests.add(identifier, std::make_unique<ServiceWorkerTerminationRequest>(*this, identifier, timeout)); |
119 | |
120 | auto& thread = serviceWorker->thread(); |
121 | thread.stop([this, identifier, serviceWorker = WTFMove(serviceWorker), completionHandler = WTFMove(completionHandler)]() mutable { |
122 | m_pendingServiceWorkerTerminationRequests.remove(identifier); |
123 | |
124 | if (auto* connection = SWContextManager::singleton().connection()) |
125 | connection->workerTerminated(identifier); |
126 | |
127 | if (completionHandler) |
128 | completionHandler(); |
129 | |
130 | // Spin the runloop before releasing the worker thread proxy, as there would otherwise be |
131 | // a race towards its destruction. |
132 | callOnMainThread([serviceWorker = WTFMove(serviceWorker)] { }); |
133 | }); |
134 | } |
135 | |
136 | void SWContextManager::forEachServiceWorkerThread(const WTF::Function<void(ServiceWorkerThreadProxy&)>& apply) |
137 | { |
138 | for (auto& workerThread : m_workerMap.values()) |
139 | apply(*workerThread); |
140 | } |
141 | |
142 | bool SWContextManager::postTaskToServiceWorker(ServiceWorkerIdentifier identifier, WTF::Function<void(ServiceWorkerGlobalScope&)>&& task) |
143 | { |
144 | auto* serviceWorker = m_workerMap.get(identifier); |
145 | if (!serviceWorker) |
146 | return false; |
147 | |
148 | serviceWorker->thread().runLoop().postTask([task = WTFMove(task)] (auto& context) { |
149 | task(downcast<ServiceWorkerGlobalScope>(context)); |
150 | }); |
151 | return true; |
152 | } |
153 | |
154 | void SWContextManager::serviceWorkerFailedToTerminate(ServiceWorkerIdentifier serviceWorkerIdentifier) |
155 | { |
156 | UNUSED_PARAM(serviceWorkerIdentifier); |
157 | RELEASE_LOG_ERROR(ServiceWorker, "Failed to terminate service worker with identifier %s, killing the service worker process" , serviceWorkerIdentifier.loggingString().utf8().data()); |
158 | _exit(EXIT_FAILURE); |
159 | } |
160 | |
161 | SWContextManager::ServiceWorkerTerminationRequest::ServiceWorkerTerminationRequest(SWContextManager& manager, ServiceWorkerIdentifier serviceWorkerIdentifier, Seconds timeout) |
162 | : m_timeoutTimer([&manager, serviceWorkerIdentifier] { manager.serviceWorkerFailedToTerminate(serviceWorkerIdentifier); }) |
163 | { |
164 | m_timeoutTimer.startOneShot(timeout); |
165 | } |
166 | |
167 | } // namespace WebCore |
168 | |
169 | #endif |
170 | |