Add a SW context process (where SW scripts will actually execute).
[WebKit-https.git] / Source / WebKit / UIProcess / WebProcessProxy.cpp
1 /*
2  * Copyright (C) 2010-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 "WebProcessProxy.h"
28
29 #include "APIFrameHandle.h"
30 #include "APIPageGroupHandle.h"
31 #include "APIPageHandle.h"
32 #include "DataReference.h"
33 #include "DownloadProxyMap.h"
34 #include "Logging.h"
35 #include "PluginInfoStore.h"
36 #include "PluginProcessManager.h"
37 #include "TextChecker.h"
38 #include "TextCheckerState.h"
39 #include "UserData.h"
40 #include "WebBackForwardListItem.h"
41 #include "WebInspectorUtilities.h"
42 #include "WebNavigationDataStore.h"
43 #include "WebNotificationManagerProxy.h"
44 #include "WebPageGroup.h"
45 #include "WebPageProxy.h"
46 #include "WebPasteboardProxy.h"
47 #include "WebProcessMessages.h"
48 #include "WebProcessPool.h"
49 #include "WebProcessProxyMessages.h"
50 #include "WebUserContentControllerProxy.h"
51 #include "WebsiteData.h"
52 #include <WebCore/DiagnosticLoggingKeys.h>
53 #include <WebCore/SuddenTermination.h>
54 #include <WebCore/URL.h>
55 #include <stdio.h>
56 #include <wtf/NeverDestroyed.h>
57 #include <wtf/RunLoop.h>
58 #include <wtf/text/CString.h>
59 #include <wtf/text/StringBuilder.h>
60 #include <wtf/text/WTFString.h>
61
62 #if PLATFORM(COCOA)
63 #include "ObjCObjectGraph.h"
64 #include "PDFPlugin.h"
65 #include "UserMediaCaptureManagerProxy.h"
66 #endif
67
68 #if ENABLE(SEC_ITEM_SHIM)
69 #include "SecItemShimProxy.h"
70 #endif
71
72 using namespace WebCore;
73
74 #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, connection())
75 #define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(checkURLReceivedFromWebProcess(url), connection())
76
77 namespace WebKit {
78
79 static uint64_t generatePageID()
80 {
81     static uint64_t uniquePageID;
82     return ++uniquePageID;
83 }
84
85 static WebProcessProxy::WebPageProxyMap& globalPageMap()
86 {
87     ASSERT(RunLoop::isMain());
88     static NeverDestroyed<WebProcessProxy::WebPageProxyMap> pageMap;
89     return pageMap;
90 }
91
92 Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool, WebsiteDataStore& websiteDataStore)
93 {
94     return adoptRef(*new WebProcessProxy(processPool, websiteDataStore));
95 }
96
97 WebProcessProxy::WebProcessProxy(WebProcessPool& processPool, WebsiteDataStore& websiteDataStore)
98     : ChildProcessProxy(processPool.alwaysRunsAtBackgroundPriority())
99     , m_responsivenessTimer(*this)
100     , m_backgroundResponsivenessTimer(*this)
101     , m_processPool(processPool)
102     , m_mayHaveUniversalFileReadSandboxExtension(false)
103     , m_numberOfTimesSuddenTerminationWasDisabled(0)
104     , m_throttler(*this, processPool.shouldTakeUIBackgroundAssertion())
105     , m_isResponsive(NoOrMaybe::Maybe)
106     , m_visiblePageCounter([this](RefCounterEvent) { updateBackgroundResponsivenessTimer(); })
107     , m_websiteDataStore(websiteDataStore)
108 #if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
109     , m_userMediaCaptureManagerProxy(std::make_unique<UserMediaCaptureManagerProxy>(*this))
110 #endif
111 {
112     WebPasteboardProxy::singleton().addWebProcessProxy(*this);
113
114     connect();
115 }
116
117 WebProcessProxy::~WebProcessProxy()
118 {
119     ASSERT(m_pageURLRetainCountMap.isEmpty());
120     
121     WebPasteboardProxy::singleton().removeWebProcessProxy(*this);
122
123     if (m_webConnection)
124         m_webConnection->invalidate();
125
126     while (m_numberOfTimesSuddenTerminationWasDisabled-- > 0)
127         WebCore::enableSuddenTermination();
128 }
129
130 void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
131 {
132     launchOptions.processType = ProcessLauncher::ProcessType::Web;
133
134     ChildProcessProxy::getLaunchOptions(launchOptions);
135
136     if (WebKit::isInspectorProcessPool(m_processPool))
137         launchOptions.extraInitializationData.add(ASCIILiteral("inspector-process"), ASCIILiteral("1"));
138
139     auto overrideLanguages = m_processPool->configuration().overrideLanguages();
140     if (overrideLanguages.size()) {
141         StringBuilder languageString;
142         for (size_t i = 0; i < overrideLanguages.size(); ++i) {
143             if (i)
144                 languageString.append(',');
145             languageString.append(overrideLanguages[i]);
146         }
147         launchOptions.extraInitializationData.add(ASCIILiteral("OverrideLanguages"), languageString.toString());
148     }
149 }
150
151 void WebProcessProxy::connectionWillOpen(IPC::Connection& connection)
152 {
153     ASSERT(this->connection() == &connection);
154
155 #if ENABLE(SEC_ITEM_SHIM)
156     SecItemShimProxy::singleton().initializeConnection(connection);
157 #endif
158
159     for (auto& page : m_pageMap.values())
160         page->connectionWillOpen(connection);
161 }
162
163 void WebProcessProxy::processWillShutDown(IPC::Connection& connection)
164 {
165     ASSERT_UNUSED(connection, this->connection() == &connection);
166
167     for (auto& page : m_pageMap.values())
168         page->webProcessWillShutDown();
169 }
170
171 void WebProcessProxy::shutDown()
172 {
173     shutDownProcess();
174
175     if (m_webConnection) {
176         m_webConnection->invalidate();
177         m_webConnection = nullptr;
178     }
179
180     m_responsivenessTimer.invalidate();
181     m_backgroundResponsivenessTimer.invalidate();
182     m_tokenForHoldingLockedFiles = nullptr;
183
184     for (auto& frame : copyToVector(m_frameMap.values()))
185         frame->webProcessWillShutDown();
186     m_frameMap.clear();
187
188     for (auto* visitedLinkStore : m_visitedLinkStores)
189         visitedLinkStore->removeProcess(*this);
190     m_visitedLinkStores.clear();
191
192     for (auto* webUserContentControllerProxy : m_webUserContentControllerProxies)
193         webUserContentControllerProxy->removeProcess(*this);
194     m_webUserContentControllerProxies.clear();
195
196     m_userInitiatedActionMap.clear();
197
198     m_processPool->disconnectProcess(this);
199 }
200
201 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID)
202 {
203     return globalPageMap().get(pageID);
204 }
205
206 void WebProcessProxy::deleteWebsiteDataForTopPrivatelyControlledDomainsInAllPersistentDataStores(OptionSet<WebsiteDataType> dataTypes, Vector<String>&& topPrivatelyControlledDomains, bool shouldNotifyPage, Function<void (const HashSet<String>&)>&& completionHandler)
207 {
208     // We expect this to be called on the main thread so we get the default website data store.
209     ASSERT(RunLoop::isMain());
210     
211     struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
212         explicit CallbackAggregator(Function<void(HashSet<String>)>&& completionHandler)
213             : completionHandler(WTFMove(completionHandler))
214         {
215         }
216         void addDomainsWithDeletedWebsiteData(const HashSet<String>& domains)
217         {
218             domainsWithDeletedWebsiteData.add(domains.begin(), domains.end());
219         }
220         
221         void addPendingCallback()
222         {
223             ++pendingCallbacks;
224         }
225         
226         void removePendingCallback()
227         {
228             ASSERT(pendingCallbacks);
229             --pendingCallbacks;
230             
231             callIfNeeded();
232         }
233         
234         void callIfNeeded()
235         {
236             if (!pendingCallbacks)
237                 completionHandler(domainsWithDeletedWebsiteData);
238         }
239         
240         unsigned pendingCallbacks = 0;
241         Function<void(HashSet<String>)> completionHandler;
242         HashSet<String> domainsWithDeletedWebsiteData;
243     };
244     
245     RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTFMove(completionHandler)));
246
247     HashSet<PAL::SessionID> visitedSessionIDs;
248     for (auto& page : globalPageMap()) {
249         auto& dataStore = page.value->websiteDataStore();
250         if (!dataStore.isPersistent() || visitedSessionIDs.contains(dataStore.sessionID()))
251             continue;
252         visitedSessionIDs.add(dataStore.sessionID());
253         callbackAggregator->addPendingCallback();
254         dataStore.removeDataForTopPrivatelyControlledDomains(dataTypes, { }, topPrivatelyControlledDomains, [callbackAggregator, shouldNotifyPage, page](HashSet<String>&& domainsWithDeletedWebsiteData) {
255             // When completing the task, we should be getting called on the main thread.
256             ASSERT(RunLoop::isMain());
257             
258             if (shouldNotifyPage)
259                 page.value->postMessageToInjectedBundle("WebsiteDataDeletionForTopPrivatelyOwnedDomainsFinished", nullptr);
260             
261             callbackAggregator->addDomainsWithDeletedWebsiteData(WTFMove(domainsWithDeletedWebsiteData));
262             callbackAggregator->removePendingCallback();
263         });
264     }
265 }
266
267 void WebProcessProxy::topPrivatelyControlledDomainsWithWebsiteData(OptionSet<WebsiteDataType> dataTypes, bool shouldNotifyPage, Function<void(HashSet<String>&&)>&& completionHandler)
268 {
269     // We expect this to be called on the main thread so we get the default website data store.
270     ASSERT(RunLoop::isMain());
271     
272     struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
273         explicit CallbackAggregator(Function<void(HashSet<String>&&)>&& completionHandler)
274             : completionHandler(WTFMove(completionHandler))
275         {
276         }
277         
278         void addDomainsWithDeletedWebsiteData(HashSet<String>&& domains)
279         {
280             domainsWithDeletedWebsiteData.add(domains.begin(), domains.end());
281         }
282         
283         void addPendingCallback()
284         {
285             ++pendingCallbacks;
286         }
287         
288         void removePendingCallback()
289         {
290             ASSERT(pendingCallbacks);
291             --pendingCallbacks;
292             
293             callIfNeeded();
294         }
295         
296         void callIfNeeded()
297         {
298             if (!pendingCallbacks)
299                 completionHandler(WTFMove(domainsWithDeletedWebsiteData));
300         }
301         
302         unsigned pendingCallbacks = 0;
303         Function<void(HashSet<String>&&)> completionHandler;
304         HashSet<String> domainsWithDeletedWebsiteData;
305     };
306     
307     RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTFMove(completionHandler)));
308     
309     HashSet<PAL::SessionID> visitedSessionIDs;
310     for (auto& page : globalPageMap()) {
311         auto& dataStore = page.value->websiteDataStore();
312         if (!dataStore.isPersistent() || visitedSessionIDs.contains(dataStore.sessionID()))
313             continue;
314         visitedSessionIDs.add(dataStore.sessionID());
315         callbackAggregator->addPendingCallback();
316         dataStore.topPrivatelyControlledDomainsWithWebsiteData(dataTypes, { }, [callbackAggregator, shouldNotifyPage, page](HashSet<String>&& domainsWithDataRecords) {
317             // When completing the task, we should be getting called on the main thread.
318             ASSERT(RunLoop::isMain());
319             
320             if (shouldNotifyPage)
321                 page.value->postMessageToInjectedBundle("WebsiteDataScanForTopPrivatelyControlledDomainsFinished", nullptr);
322             
323             callbackAggregator->addDomainsWithDeletedWebsiteData(WTFMove(domainsWithDataRecords));
324             callbackAggregator->removePendingCallback();
325         });
326     }
327
328     // FIXME: It's bizarre that this call is on WebProcessProxy and that it doesn't work if there are no visited pages.
329     // This should actually be a function of WebsiteDataStore and it should work even if there are no WebViews instances.
330     callbackAggregator->callIfNeeded();
331 }
332     
333 void WebProcessProxy::notifyPageStatisticsAndDataRecordsProcessed()
334 {
335     for (auto& page : globalPageMap())
336         page.value->postMessageToInjectedBundle("WebsiteDataScanForTopPrivatelyControlledDomainsFinished", nullptr);
337 }
338     
339 void WebProcessProxy::notifyPageStatisticsTelemetryFinished(API::Object* messageBody)
340 {
341     for (auto& page : globalPageMap())
342         page.value->postMessageToInjectedBundle("ResourceLoadStatisticsTelemetryFinished", messageBody);
343 }
344     
345 Ref<WebPageProxy> WebProcessProxy::createWebPage(PageClient& pageClient, Ref<API::PageConfiguration>&& pageConfiguration)
346 {
347     uint64_t pageID = generatePageID();
348     Ref<WebPageProxy> webPage = WebPageProxy::create(pageClient, *this, pageID, WTFMove(pageConfiguration));
349
350     addExistingWebPage(webPage.get(), pageID);
351
352     return webPage;
353 }
354
355 void WebProcessProxy::addExistingWebPage(WebPageProxy& webPage, uint64_t pageID)
356 {
357     ASSERT(!m_pageMap.contains(pageID));
358     ASSERT(!globalPageMap().contains(pageID));
359
360     m_processPool->pageAddedToProcess(webPage);
361
362     m_pageMap.set(pageID, &webPage);
363     globalPageMap().set(pageID, &webPage);
364
365     updateBackgroundResponsivenessTimer();
366 }
367
368 void WebProcessProxy::removeWebPage(WebPageProxy& webPage, uint64_t pageID)
369 {
370     auto* removedPage = m_pageMap.take(pageID);
371     ASSERT_UNUSED(removedPage, removedPage == &webPage);
372     removedPage = globalPageMap().take(pageID);
373     ASSERT_UNUSED(removedPage, removedPage == &webPage);
374
375     m_processPool->pageRemovedFromProcess(webPage);
376
377     updateBackgroundResponsivenessTimer();
378     
379     Vector<uint64_t> itemIDsToRemove;
380     for (auto& idAndItem : m_backForwardListItemMap) {
381         if (idAndItem.value->pageID() == pageID)
382             itemIDsToRemove.append(idAndItem.key);
383     }
384     for (auto itemID : itemIDsToRemove)
385         m_backForwardListItemMap.remove(itemID);
386
387     // If this was the last WebPage open in that web process, and we have no other reason to keep it alive, let it go.
388     // We only allow this when using a network process, as otherwise the WebProcess needs to preserve its session state.
389     if (state() == State::Terminated || !canTerminateChildProcess())
390         return;
391
392     shutDown();
393 }
394
395 void WebProcessProxy::addVisitedLinkStore(VisitedLinkStore& store)
396 {
397     m_visitedLinkStores.add(&store);
398     store.addProcess(*this);
399 }
400
401 void WebProcessProxy::addWebUserContentControllerProxy(WebUserContentControllerProxy& proxy, WebPageCreationParameters& parameters)
402 {
403     m_webUserContentControllerProxies.add(&proxy);
404     proxy.addProcess(*this, parameters);
405 }
406
407 void WebProcessProxy::didDestroyVisitedLinkStore(VisitedLinkStore& store)
408 {
409     ASSERT(m_visitedLinkStores.contains(&store));
410     m_visitedLinkStores.remove(&store);
411 }
412
413 void WebProcessProxy::didDestroyWebUserContentControllerProxy(WebUserContentControllerProxy& proxy)
414 {
415     ASSERT(m_webUserContentControllerProxies.contains(&proxy));
416     m_webUserContentControllerProxies.remove(&proxy);
417 }
418
419 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
420 {
421     return m_backForwardListItemMap.get(itemID);
422 }
423
424 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem& item)
425 {
426     // This item was just created by the UIProcess and is being added to the map for the first time
427     // so we should not already have an item for this ID.
428     ASSERT(!m_backForwardListItemMap.contains(item.itemID()));
429
430     m_backForwardListItemMap.set(item.itemID(), &item);
431 }
432
433 void WebProcessProxy::removeBackForwardItem(uint64_t itemID)
434 {
435     m_backForwardListItemMap.remove(itemID);
436 }
437
438 void WebProcessProxy::assumeReadAccessToBaseURL(const String& urlString)
439 {
440     URL url(URL(), urlString);
441     if (!url.isLocalFile())
442         return;
443
444     // There's a chance that urlString does not point to a directory.
445     // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
446     URL baseURL(URL(), url.baseAsString());
447     
448     // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
449     // to have read access to this directory already.
450     m_localPathsWithAssumedReadAccess.add(baseURL.fileSystemPath());
451 }
452
453 bool WebProcessProxy::hasAssumedReadAccessToURL(const URL& url) const
454 {
455     if (!url.isLocalFile())
456         return false;
457
458     String path = url.fileSystemPath();
459     auto startsWithURLPath = [&path](const String& assumedAccessPath) {
460         // There are no ".." components, because URL removes those.
461         return path.startsWith(assumedAccessPath);
462     };
463
464     auto& platformPaths = platformPathsWithAssumedReadAccess();
465     auto platformPathsEnd = platformPaths.end();
466     if (std::find_if(platformPaths.begin(), platformPathsEnd, startsWithURLPath) != platformPathsEnd)
467         return true;
468
469     auto localPathsEnd = m_localPathsWithAssumedReadAccess.end();
470     if (std::find_if(m_localPathsWithAssumedReadAccess.begin(), localPathsEnd, startsWithURLPath) != localPathsEnd)
471         return true;
472
473     return false;
474 }
475
476 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
477 {
478     return checkURLReceivedFromWebProcess(URL(URL(), urlString));
479 }
480
481 bool WebProcessProxy::checkURLReceivedFromWebProcess(const URL& url)
482 {
483     // FIXME: Consider checking that the URL is valid. Currently, WebProcess sends invalid URLs in many cases, but it probably doesn't have good reasons to do that.
484
485     // Any other non-file URL is OK.
486     if (!url.isLocalFile())
487         return true;
488
489     // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
490     if (m_mayHaveUniversalFileReadSandboxExtension)
491         return true;
492
493     // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
494     if (hasAssumedReadAccessToURL(url))
495         return true;
496
497     // Items in back/forward list have been already checked.
498     // One case where we don't have sandbox extensions for file URLs in b/f list is if the list has been reinstated after a crash or a browser restart.
499     String path = url.fileSystemPath();
500     for (WebBackForwardListItemMap::iterator iter = m_backForwardListItemMap.begin(), end = m_backForwardListItemMap.end(); iter != end; ++iter) {
501         URL itemURL(URL(), iter->value->url());
502         if (itemURL.isLocalFile() && itemURL.fileSystemPath() == path)
503             return true;
504         URL itemOriginalURL(URL(), iter->value->originalURL());
505         if (itemOriginalURL.isLocalFile() && itemOriginalURL.fileSystemPath() == path)
506             return true;
507     }
508
509     // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
510     WTFLogAlways("Received an unexpected URL from the web process: '%s'\n", url.string().utf8().data());
511     return false;
512 }
513
514 #if !PLATFORM(COCOA)
515 bool WebProcessProxy::fullKeyboardAccessEnabled()
516 {
517     return false;
518 }
519 #endif
520
521 void WebProcessProxy::addBackForwardItem(uint64_t itemID, uint64_t pageID, const PageState& pageState)
522 {
523     MESSAGE_CHECK_URL(pageState.mainFrameState.originalURLString);
524     MESSAGE_CHECK_URL(pageState.mainFrameState.urlString);
525
526     auto& backForwardListItem = m_backForwardListItemMap.add(itemID, nullptr).iterator->value;
527     if (!backForwardListItem) {
528         BackForwardListItemState backForwardListItemState;
529         backForwardListItemState.identifier = itemID;
530         backForwardListItemState.pageState = pageState;
531         backForwardListItem = WebBackForwardListItem::create(WTFMove(backForwardListItemState), pageID);
532         return;
533     }
534
535     // Update existing item.
536     backForwardListItem->setPageState(pageState);
537 }
538
539 #if ENABLE(NETSCAPE_PLUGIN_API)
540 void WebProcessProxy::getPlugins(bool refresh, Vector<PluginInfo>& plugins, Vector<PluginInfo>& applicationPlugins)
541 {
542     if (refresh)
543         m_processPool->pluginInfoStore().refresh();
544
545     Vector<PluginModuleInfo> pluginModules = m_processPool->pluginInfoStore().plugins();
546     for (size_t i = 0; i < pluginModules.size(); ++i)
547         plugins.append(pluginModules[i].info);
548
549 #if ENABLE(PDFKIT_PLUGIN)
550     // Add built-in PDF last, so that it's not used when a real plug-in is installed.
551     if (!m_processPool->omitPDFSupport()) {
552         plugins.append(PDFPlugin::pluginInfo());
553         applicationPlugins.append(PDFPlugin::pluginInfo());
554     }
555 #else
556     UNUSED_PARAM(applicationPlugins);
557 #endif
558 }
559 #endif // ENABLE(NETSCAPE_PLUGIN_API)
560
561 #if ENABLE(NETSCAPE_PLUGIN_API)
562 void WebProcessProxy::getPluginProcessConnection(uint64_t pluginProcessToken, Ref<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply>&& reply)
563 {
564     PluginProcessManager::singleton().getPluginProcessConnection(pluginProcessToken, WTFMove(reply));
565 }
566 #endif
567
568 void WebProcessProxy::getNetworkProcessConnection(Ref<Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply>&& reply)
569 {
570     m_processPool->getNetworkProcessConnection(WTFMove(reply));
571 }
572
573 void WebProcessProxy::getStorageProcessConnection(Ref<Messages::WebProcessProxy::GetStorageProcessConnection::DelayedReply>&& reply)
574 {
575     m_processPool->getStorageProcessConnection(WTFMove(reply));
576 }
577
578 #if !PLATFORM(COCOA)
579 bool WebProcessProxy::platformIsBeingDebugged() const
580 {
581     return false;
582 }
583 #endif
584
585 void WebProcessProxy::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
586 {
587     if (dispatchMessage(connection, decoder))
588         return;
589
590     if (m_processPool->dispatchMessage(connection, decoder))
591         return;
592
593     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
594         didReceiveWebProcessProxyMessage(connection, decoder);
595         return;
596     }
597
598     // FIXME: Add unhandled message logging.
599 }
600
601 void WebProcessProxy::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& replyEncoder)
602 {
603     if (dispatchSyncMessage(connection, decoder, replyEncoder))
604         return;
605
606     if (m_processPool->dispatchSyncMessage(connection, decoder, replyEncoder))
607         return;
608
609     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
610         didReceiveSyncWebProcessProxyMessage(connection, decoder, replyEncoder);
611         return;
612     }
613
614     // FIXME: Add unhandled message logging.
615 }
616
617 void WebProcessProxy::didClose(IPC::Connection&)
618 {
619     // Protect ourselves, as the call to disconnect() below may otherwise cause us
620     // to be deleted before we can finish our work.
621     Ref<WebProcessProxy> protect(*this);
622
623     webConnection()->didClose();
624
625     auto pages = copyToVector(m_pageMap.values());
626
627     shutDown();
628
629     for (auto& page : pages)
630         page->processDidTerminate(ProcessTerminationReason::Crash);
631
632 }
633
634 void WebProcessProxy::didReceiveInvalidMessage(IPC::Connection& connection, IPC::StringReference messageReceiverName, IPC::StringReference messageName)
635 {
636     WTFLogAlways("Received an invalid message \"%s.%s\" from the web process.\n", messageReceiverName.toString().data(), messageName.toString().data());
637
638     WebProcessPool::didReceiveInvalidMessage(messageReceiverName, messageName);
639
640     // Terminate the WebProcess.
641     terminate();
642
643     // Since we've invalidated the connection we'll never get a IPC::Connection::Client::didClose
644     // callback so we'll explicitly call it here instead.
645     didClose(connection);
646 }
647
648 void WebProcessProxy::didBecomeUnresponsive()
649 {
650     m_isResponsive = NoOrMaybe::No;
651
652     auto isResponsiveCallbacks = WTFMove(m_isResponsiveCallbacks);
653
654     for (auto& page : copyToVector(m_pageMap.values()))
655         page->processDidBecomeUnresponsive();
656
657     bool isWebProcessResponsive = false;
658     for (auto& callback : isResponsiveCallbacks)
659         callback(isWebProcessResponsive);
660 }
661
662 void WebProcessProxy::didBecomeResponsive()
663 {
664     m_isResponsive = NoOrMaybe::Maybe;
665
666     for (auto& page : copyToVector(m_pageMap.values()))
667         page->processDidBecomeResponsive();
668 }
669
670 void WebProcessProxy::willChangeIsResponsive()
671 {
672     for (auto& page : copyToVector(m_pageMap.values()))
673         page->willChangeProcessIsResponsive();
674 }
675
676 void WebProcessProxy::didChangeIsResponsive()
677 {
678     for (auto& page : copyToVector(m_pageMap.values()))
679         page->didChangeProcessIsResponsive();
680 }
681
682 bool WebProcessProxy::mayBecomeUnresponsive()
683 {
684     return !platformIsBeingDebugged();
685 }
686
687 void WebProcessProxy::didFinishLaunching(ProcessLauncher* launcher, IPC::Connection::Identifier connectionIdentifier)
688 {
689     ChildProcessProxy::didFinishLaunching(launcher, connectionIdentifier);
690
691     for (WebPageProxy* page : m_pageMap.values()) {
692         ASSERT(this == &page->process());
693         page->processDidFinishLaunching();
694     }
695
696     m_webConnection = WebConnectionToWebProcess::create(this);
697
698     m_processPool->processDidFinishLaunching(this);
699
700 #if PLATFORM(IOS)
701     if (connection()) {
702         if (xpc_connection_t xpcConnection = connection()->xpcConnection())
703             m_throttler.didConnectToProcess(xpc_connection_get_pid(xpcConnection));
704     }
705 #endif
706 }
707
708 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
709 {
710     if (!WebFrameProxyMap::isValidKey(frameID))
711         return 0;
712
713     return m_frameMap.get(frameID);
714 }
715
716 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
717 {
718     return WebFrameProxyMap::isValidKey(frameID) && !m_frameMap.contains(frameID);
719 }
720
721 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
722 {
723     ASSERT(canCreateFrame(frameID));
724     m_frameMap.set(frameID, frameProxy);
725 }
726
727 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
728 {
729     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
730     // back to the UIProcess, then the frameDestroyed message will still be received because it
731     // gets sent directly to the WebProcessProxy.
732     ASSERT(WebFrameProxyMap::isValidKey(frameID));
733     m_frameMap.remove(frameID);
734 }
735
736 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
737 {
738     for (auto& frame : copyToVector(m_frameMap.values())) {
739         if (frame->page() == page)
740             frame->webProcessWillShutDown();
741     }
742 }
743
744 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
745 {
746     size_t result = 0;
747     for (auto& frame : m_frameMap.values()) {
748         if (frame->page() == page)
749             ++result;
750     }
751     return result;
752 }
753
754 auto WebProcessProxy::visiblePageToken() const -> VisibleWebPageToken
755 {
756     return m_visiblePageCounter.count();
757 }
758
759 RefPtr<API::UserInitiatedAction> WebProcessProxy::userInitiatedActivity(uint64_t identifier)
760 {
761     if (!UserInitiatedActionMap::isValidKey(identifier) || !identifier)
762         return nullptr;
763
764     auto result = m_userInitiatedActionMap.ensure(identifier, [] { return API::UserInitiatedAction::create(); });
765     return result.iterator->value;
766 }
767
768 bool WebProcessProxy::isResponsive() const
769 {
770     return m_responsivenessTimer.isResponsive() && m_backgroundResponsivenessTimer.isResponsive();
771 }
772
773 void WebProcessProxy::didDestroyUserGestureToken(uint64_t identifier)
774 {
775     ASSERT(UserInitiatedActionMap::isValidKey(identifier));
776     m_userInitiatedActionMap.remove(identifier);
777 }
778
779 bool WebProcessProxy::canTerminateChildProcess()
780 {
781     if (!m_pageMap.isEmpty())
782         return false;
783
784     if (!m_processPool->shouldTerminate(this))
785         return false;
786
787     return true;
788 }
789
790 void WebProcessProxy::shouldTerminate(bool& shouldTerminate)
791 {
792     shouldTerminate = canTerminateChildProcess();
793     if (shouldTerminate) {
794         // We know that the web process is going to terminate so start shutting it down in the UI process.
795         shutDown();
796     }
797 }
798
799 void WebProcessProxy::updateTextCheckerState()
800 {
801     if (canSendMessage())
802         send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
803 }
804
805 void WebProcessProxy::didSaveToPageCache()
806 {
807     m_processPool->processDidCachePage(this);
808 }
809
810 void WebProcessProxy::releasePageCache()
811 {
812     if (canSendMessage())
813         send(Messages::WebProcess::ReleasePageCache(), 0);
814 }
815
816 void WebProcessProxy::windowServerConnectionStateChanged()
817 {
818     for (const auto& page : m_pageMap.values())
819         page->activityStateDidChange(ActivityState::IsVisuallyIdle);
820 }
821
822 void WebProcessProxy::fetchWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, Function<void(WebsiteData)>&& completionHandler)
823 {
824     ASSERT(canSendMessage());
825
826     auto token = throttler().backgroundActivityToken();
827     RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because the Web process is fetching Website data", this);
828
829     connection()->sendWithReply(Messages::WebProcess::FetchWebsiteData(sessionID, dataTypes), 0, RunLoop::main(), [this, token, completionHandler = WTFMove(completionHandler), sessionID](auto reply) {
830         if (!reply) {
831             completionHandler(WebsiteData { });
832             return;
833         }
834
835         completionHandler(WTFMove(std::get<0>(*reply)));
836         RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is releasing a background assertion because the Web process is done fetching Website data", this);
837     });
838 }
839
840 void WebProcessProxy::deleteWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, std::chrono::system_clock::time_point modifiedSince, Function<void()>&& completionHandler)
841 {
842     ASSERT(canSendMessage());
843
844     auto token = throttler().backgroundActivityToken();
845     RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because the Web process is deleting Website data", this);
846
847     connection()->sendWithReply(Messages::WebProcess::DeleteWebsiteData(sessionID, dataTypes, modifiedSince), 0, RunLoop::main(), [this, token, completionHandler = WTFMove(completionHandler), sessionID](auto reply) {
848         completionHandler();
849         RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is releasing a background assertion because the Web process is done deleting Website data", this);
850     });
851 }
852
853 void WebProcessProxy::deleteWebsiteDataForOrigins(PAL::SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, const Vector<WebCore::SecurityOriginData>& origins, Function<void()>&& completionHandler)
854 {
855     ASSERT(canSendMessage());
856
857     auto token = throttler().backgroundActivityToken();
858     RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because the Web process is deleting Website data for several origins", this);
859
860     connection()->sendWithReply(Messages::WebProcess::DeleteWebsiteDataForOrigins(sessionID, dataTypes, origins), 0, RunLoop::main(), [this, token, completionHandler = WTFMove(completionHandler), sessionID](auto reply) {
861         completionHandler();
862         RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is releasing a background assertion because the Web process is done deleting Website data for several origins", this);
863     });
864 }
865
866 void WebProcessProxy::requestTermination(ProcessTerminationReason reason)
867 {
868     if (state() == State::Terminated)
869         return;
870
871     ChildProcessProxy::terminate();
872
873     if (webConnection())
874         webConnection()->didClose();
875
876     auto pages = copyToVector(m_pageMap.values());
877
878     shutDown();
879
880     for (auto& page : pages)
881         page->processDidTerminate(reason);
882 }
883
884 void WebProcessProxy::stopResponsivenessTimer()
885 {
886     responsivenessTimer().stop();
887 }
888
889 void WebProcessProxy::enableSuddenTermination()
890 {
891     if (state() != State::Running)
892         return;
893
894     ASSERT(m_numberOfTimesSuddenTerminationWasDisabled);
895     WebCore::enableSuddenTermination();
896     --m_numberOfTimesSuddenTerminationWasDisabled;
897 }
898
899 void WebProcessProxy::disableSuddenTermination()
900 {
901     if (state() != State::Running)
902         return;
903
904     WebCore::disableSuddenTermination();
905     ++m_numberOfTimesSuddenTerminationWasDisabled;
906 }
907
908 RefPtr<API::Object> WebProcessProxy::transformHandlesToObjects(API::Object* object)
909 {
910     struct Transformer final : UserData::Transformer {
911         Transformer(WebProcessProxy& webProcessProxy)
912             : m_webProcessProxy(webProcessProxy)
913         {
914         }
915
916         bool shouldTransformObject(const API::Object& object) const override
917         {
918             switch (object.type()) {
919             case API::Object::Type::FrameHandle:
920                 return static_cast<const API::FrameHandle&>(object).isAutoconverting();
921
922             case API::Object::Type::PageHandle:
923                 return static_cast<const API::PageHandle&>(object).isAutoconverting();
924
925             case API::Object::Type::PageGroupHandle:
926 #if PLATFORM(COCOA)
927             case API::Object::Type::ObjCObjectGraph:
928 #endif
929                 return true;
930
931             default:
932                 return false;
933             }
934         }
935
936         RefPtr<API::Object> transformObject(API::Object& object) const override
937         {
938             switch (object.type()) {
939             case API::Object::Type::FrameHandle:
940                 ASSERT(static_cast<API::FrameHandle&>(object).isAutoconverting());
941                 return m_webProcessProxy.webFrame(static_cast<API::FrameHandle&>(object).frameID());
942
943             case API::Object::Type::PageGroupHandle:
944                 return WebPageGroup::get(static_cast<API::PageGroupHandle&>(object).webPageGroupData().pageGroupID);
945
946             case API::Object::Type::PageHandle:
947                 ASSERT(static_cast<API::PageHandle&>(object).isAutoconverting());
948                 return m_webProcessProxy.webPage(static_cast<API::PageHandle&>(object).pageID());
949
950 #if PLATFORM(COCOA)
951             case API::Object::Type::ObjCObjectGraph:
952                 return m_webProcessProxy.transformHandlesToObjects(static_cast<ObjCObjectGraph&>(object));
953 #endif
954             default:
955                 return &object;
956             }
957         }
958
959         WebProcessProxy& m_webProcessProxy;
960     };
961
962     return UserData::transform(object, Transformer(*this));
963 }
964
965 RefPtr<API::Object> WebProcessProxy::transformObjectsToHandles(API::Object* object)
966 {
967     struct Transformer final : UserData::Transformer {
968         bool shouldTransformObject(const API::Object& object) const override
969         {
970             switch (object.type()) {
971             case API::Object::Type::Frame:
972             case API::Object::Type::Page:
973             case API::Object::Type::PageGroup:
974 #if PLATFORM(COCOA)
975             case API::Object::Type::ObjCObjectGraph:
976 #endif
977                 return true;
978
979             default:
980                 return false;
981             }
982         }
983
984         RefPtr<API::Object> transformObject(API::Object& object) const override
985         {
986             switch (object.type()) {
987             case API::Object::Type::Frame:
988                 return API::FrameHandle::createAutoconverting(static_cast<const WebFrameProxy&>(object).frameID());
989
990             case API::Object::Type::Page:
991                 return API::PageHandle::createAutoconverting(static_cast<const WebPageProxy&>(object).pageID());
992
993             case API::Object::Type::PageGroup:
994                 return API::PageGroupHandle::create(WebPageGroupData(static_cast<const WebPageGroup&>(object).data()));
995
996 #if PLATFORM(COCOA)
997             case API::Object::Type::ObjCObjectGraph:
998                 return transformObjectsToHandles(static_cast<ObjCObjectGraph&>(object));
999 #endif
1000
1001             default:
1002                 return &object;
1003             }
1004         }
1005     };
1006
1007     return UserData::transform(object, Transformer());
1008 }
1009
1010 void WebProcessProxy::sendProcessWillSuspendImminently()
1011 {
1012     if (!canSendMessage())
1013         return;
1014
1015     bool handled = false;
1016     sendSync(Messages::WebProcess::ProcessWillSuspendImminently(), Messages::WebProcess::ProcessWillSuspendImminently::Reply(handled), 0, 1_s);
1017 }
1018
1019 void WebProcessProxy::sendPrepareToSuspend()
1020 {
1021     if (canSendMessage())
1022         send(Messages::WebProcess::PrepareToSuspend(), 0);
1023 }
1024
1025 void WebProcessProxy::sendCancelPrepareToSuspend()
1026 {
1027     if (canSendMessage())
1028         send(Messages::WebProcess::CancelPrepareToSuspend(), 0);
1029 }
1030
1031 void WebProcessProxy::sendProcessDidResume()
1032 {
1033     if (canSendMessage())
1034         send(Messages::WebProcess::ProcessDidResume(), 0);
1035 }
1036
1037 void WebProcessProxy::processReadyToSuspend()
1038 {
1039     m_throttler.processReadyToSuspend();
1040 }
1041
1042 void WebProcessProxy::didCancelProcessSuspension()
1043 {
1044     m_throttler.didCancelProcessSuspension();
1045 }
1046
1047 void WebProcessProxy::reinstateNetworkProcessAssertionState(NetworkProcessProxy& newNetworkProcessProxy)
1048 {
1049 #if PLATFORM(IOS)
1050     ASSERT(!m_backgroundTokenForNetworkProcess || !m_foregroundTokenForNetworkProcess);
1051
1052     // The network process crashed; take new tokens for the new network process.
1053     if (m_backgroundTokenForNetworkProcess)
1054         m_backgroundTokenForNetworkProcess = newNetworkProcessProxy.throttler().backgroundActivityToken();
1055     else if (m_foregroundTokenForNetworkProcess)
1056         m_foregroundTokenForNetworkProcess = newNetworkProcessProxy.throttler().foregroundActivityToken();
1057 #else
1058     UNUSED_PARAM(newNetworkProcessProxy);
1059 #endif
1060 }
1061
1062 void WebProcessProxy::didSetAssertionState(AssertionState state)
1063 {
1064 #if PLATFORM(IOS)
1065     ASSERT(!m_backgroundTokenForNetworkProcess || !m_foregroundTokenForNetworkProcess);
1066
1067     switch (state) {
1068     case AssertionState::Suspended:
1069         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Suspended) release all assertions for network process", this);
1070         m_foregroundTokenForNetworkProcess = nullptr;
1071         m_backgroundTokenForNetworkProcess = nullptr;
1072         for (auto& page : m_pageMap.values())
1073             page->processWillBecomeSuspended();
1074         break;
1075
1076     case AssertionState::Background:
1077         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Background) taking background assertion for network process", this);
1078         m_backgroundTokenForNetworkProcess = processPool().ensureNetworkProcess().throttler().backgroundActivityToken();
1079         m_foregroundTokenForNetworkProcess = nullptr;
1080         break;
1081     
1082     case AssertionState::Foreground:
1083         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Foreground) taking foreground assertion for network process", this);
1084         m_foregroundTokenForNetworkProcess = processPool().ensureNetworkProcess().throttler().foregroundActivityToken();
1085         m_backgroundTokenForNetworkProcess = nullptr;
1086         for (auto& page : m_pageMap.values())
1087             page->processWillBecomeForeground();
1088         break;
1089     }
1090
1091     ASSERT(!m_backgroundTokenForNetworkProcess || !m_foregroundTokenForNetworkProcess);
1092 #else
1093     UNUSED_PARAM(state);
1094 #endif
1095 }
1096     
1097 void WebProcessProxy::setIsHoldingLockedFiles(bool isHoldingLockedFiles)
1098 {
1099     if (!isHoldingLockedFiles) {
1100         RELEASE_LOG(ProcessSuspension, "UIProcess is releasing a background assertion because the WebContent process is no longer holding locked files");
1101         m_tokenForHoldingLockedFiles = nullptr;
1102         return;
1103     }
1104     if (!m_tokenForHoldingLockedFiles) {
1105         RELEASE_LOG(ProcessSuspension, "UIProcess is taking a background assertion because the WebContent process is holding locked files");
1106         m_tokenForHoldingLockedFiles = m_throttler.backgroundActivityToken();
1107     }
1108 }
1109
1110 void WebProcessProxy::isResponsive(WTF::Function<void(bool isWebProcessResponsive)>&& callback)
1111 {
1112     if (m_isResponsive == NoOrMaybe::No) {
1113         if (callback) {
1114             RunLoop::main().dispatch([callback = WTFMove(callback)] {
1115                 bool isWebProcessResponsive = false;
1116                 callback(isWebProcessResponsive);
1117             });
1118         }
1119         return;
1120     }
1121
1122     if (callback)
1123         m_isResponsiveCallbacks.append(WTFMove(callback));
1124
1125     responsivenessTimer().start();
1126     send(Messages::WebProcess::MainThreadPing(), 0);
1127 }
1128
1129 void WebProcessProxy::didReceiveMainThreadPing()
1130 {
1131     responsivenessTimer().stop();
1132
1133     auto isResponsiveCallbacks = WTFMove(m_isResponsiveCallbacks);
1134     bool isWebProcessResponsive = true;
1135     for (auto& callback : isResponsiveCallbacks)
1136         callback(isWebProcessResponsive);
1137 }
1138
1139 void WebProcessProxy::didReceiveBackgroundResponsivenessPing()
1140 {
1141     m_backgroundResponsivenessTimer.didReceiveBackgroundResponsivenessPong();
1142 }
1143
1144 void WebProcessProxy::processTerminated()
1145 {
1146     m_responsivenessTimer.processTerminated();
1147     m_backgroundResponsivenessTimer.processTerminated();
1148 }
1149
1150 void WebProcessProxy::logDiagnosticMessageForResourceLimitTermination(const String& limitKey)
1151 {
1152     if (pageCount())
1153         (*pages().begin())->logDiagnosticMessage(DiagnosticLoggingKeys::simulatedPageCrashKey(), limitKey, ShouldSample::No);
1154 }
1155
1156 void WebProcessProxy::didExceedInactiveMemoryLimitWhileActive()
1157 {
1158     for (auto& page : pages())
1159         page->didExceedInactiveMemoryLimitWhileActive();
1160 }
1161
1162 void WebProcessProxy::didExceedActiveMemoryLimit()
1163 {
1164     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedActiveMemoryLimit() Terminating WebProcess with pid %d that has exceeded the active memory limit", this, processIdentifier());
1165     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededActiveMemoryLimitKey());
1166     requestTermination(ProcessTerminationReason::ExceededMemoryLimit);
1167 }
1168
1169 void WebProcessProxy::didExceedInactiveMemoryLimit()
1170 {
1171     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedInactiveMemoryLimit() Terminating WebProcess with pid %d that has exceeded the inactive memory limit", this, processIdentifier());
1172     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededInactiveMemoryLimitKey());
1173     requestTermination(ProcessTerminationReason::ExceededMemoryLimit);
1174 }
1175
1176 void WebProcessProxy::didExceedCPULimit()
1177 {
1178     for (auto& page : pages()) {
1179         if (page->isPlayingAudio()) {
1180             RELEASE_LOG(PerformanceLogging, "%p - WebProcessProxy::didExceedCPULimit() WebProcess with pid %d has exceeded the background CPU limit but we are not terminating it because there is audio playing", this, processIdentifier());
1181             return;
1182         }
1183
1184         if (page->hasActiveAudioStream() || page->hasActiveVideoStream()) {
1185             RELEASE_LOG(PerformanceLogging, "%p - WebProcessProxy::didExceedCPULimit() WebProcess with pid %d has exceeded the background CPU limit but we are not terminating it because it is capturing audio / video", this, processIdentifier());
1186             return;
1187         }
1188     }
1189
1190     bool hasVisiblePage = false;
1191     for (auto& page : pages()) {
1192         if (page->isViewVisible()) {
1193             page->didExceedBackgroundCPULimitWhileInForeground();
1194             hasVisiblePage = true;
1195         }
1196     }
1197
1198     // We only notify the client that the process exceeded the CPU limit when it is visible, we do not terminate it.
1199     if (hasVisiblePage)
1200         return;
1201
1202     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedCPULimit() Terminating background WebProcess with pid %d that has exceeded the background CPU limit", this, processIdentifier());
1203     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededBackgroundCPULimitKey());
1204     requestTermination(ProcessTerminationReason::ExceededCPULimit);
1205 }
1206
1207 void WebProcessProxy::updateBackgroundResponsivenessTimer()
1208 {
1209     m_backgroundResponsivenessTimer.updateState();
1210 }
1211
1212 #if !PLATFORM(COCOA)
1213 const HashSet<String>& WebProcessProxy::platformPathsWithAssumedReadAccess()
1214 {
1215     static NeverDestroyed<HashSet<String>> platformPathsWithAssumedReadAccess;
1216     return platformPathsWithAssumedReadAccess;
1217 }
1218 #endif
1219
1220 #if ENABLE(SERVICE_WORKER)
1221 void WebProcessProxy::didGetWorkerContextConnection(const IPC::Attachment& connection)
1222 {
1223     m_processPool->didGetWorkerContextProcessConnection(connection);
1224 }
1225 #endif
1226
1227 } // namespace WebKit