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