Unreviewed, rolling out r219990.
[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     Vector<RefPtr<WebFrameProxy>> frames;
185     copyValuesToVector(m_frameMap, frames);
186
187     for (size_t i = 0, size = frames.size(); i < size; ++i)
188         frames[i]->webProcessWillShutDown();
189     m_frameMap.clear();
190
191     for (VisitedLinkStore* visitedLinkStore : m_visitedLinkStores)
192         visitedLinkStore->removeProcess(*this);
193     m_visitedLinkStores.clear();
194
195     for (WebUserContentControllerProxy* webUserContentControllerProxy : m_webUserContentControllerProxies)
196         webUserContentControllerProxy->removeProcess(*this);
197     m_webUserContentControllerProxies.clear();
198
199     m_userInitiatedActionMap.clear();
200
201     m_processPool->disconnectProcess(this);
202 }
203
204 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID)
205 {
206     return globalPageMap().get(pageID);
207 }
208
209 void WebProcessProxy::deleteWebsiteDataForTopPrivatelyControlledDomainsInAllPersistentDataStores(OptionSet<WebsiteDataType> dataTypes, Vector<String>&& topPrivatelyControlledDomains, bool shouldNotifyPage, Function<void (const HashSet<String>&)>&& completionHandler)
210 {
211     // We expect this to be called on the main thread so we get the default website data store.
212     ASSERT(RunLoop::isMain());
213     
214     struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
215         explicit CallbackAggregator(Function<void(HashSet<String>)>&& completionHandler)
216             : completionHandler(WTFMove(completionHandler))
217         {
218         }
219         void addDomainsWithDeletedWebsiteData(const HashSet<String>& domains)
220         {
221             domainsWithDeletedWebsiteData.add(domains.begin(), domains.end());
222         }
223         
224         void addPendingCallback()
225         {
226             ++pendingCallbacks;
227         }
228         
229         void removePendingCallback()
230         {
231             ASSERT(pendingCallbacks);
232             --pendingCallbacks;
233             
234             callIfNeeded();
235         }
236         
237         void callIfNeeded()
238         {
239             if (!pendingCallbacks)
240                 completionHandler(domainsWithDeletedWebsiteData);
241         }
242         
243         unsigned pendingCallbacks = 0;
244         Function<void(HashSet<String>)> completionHandler;
245         HashSet<String> domainsWithDeletedWebsiteData;
246     };
247     
248     RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTFMove(completionHandler)));
249
250     HashSet<WebCore::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, { }, 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<WebCore::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->pageAddedToProcess(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->pageRemovedFromProcess(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     
451     // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
452     // to have read access to this directory already.
453     m_localPathsWithAssumedReadAccess.add(baseURL.fileSystemPath());
454 }
455
456 bool WebProcessProxy::hasAssumedReadAccessToURL(const URL& url) const
457 {
458     if (!url.isLocalFile())
459         return false;
460
461     String path = url.fileSystemPath();
462     auto startsWithURLPath = [&path](const String& assumedAccessPath) {
463         // There are no ".." components, because URL removes those.
464         return path.startsWith(assumedAccessPath);
465     };
466
467     auto& platformPaths = platformPathsWithAssumedReadAccess();
468     auto platformPathsEnd = platformPaths.end();
469     if (std::find_if(platformPaths.begin(), platformPathsEnd, startsWithURLPath) != platformPathsEnd)
470         return true;
471
472     auto localPathsEnd = m_localPathsWithAssumedReadAccess.end();
473     if (std::find_if(m_localPathsWithAssumedReadAccess.begin(), localPathsEnd, startsWithURLPath) != localPathsEnd)
474         return true;
475
476     return false;
477 }
478
479 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
480 {
481     return checkURLReceivedFromWebProcess(URL(URL(), urlString));
482 }
483
484 bool WebProcessProxy::checkURLReceivedFromWebProcess(const URL& url)
485 {
486     // 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.
487
488     // Any other non-file URL is OK.
489     if (!url.isLocalFile())
490         return true;
491
492     // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
493     if (m_mayHaveUniversalFileReadSandboxExtension)
494         return true;
495
496     // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
497     if (hasAssumedReadAccessToURL(url))
498         return true;
499
500     // Items in back/forward list have been already checked.
501     // 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.
502     String path = url.fileSystemPath();
503     for (WebBackForwardListItemMap::iterator iter = m_backForwardListItemMap.begin(), end = m_backForwardListItemMap.end(); iter != end; ++iter) {
504         URL itemURL(URL(), iter->value->url());
505         if (itemURL.isLocalFile() && itemURL.fileSystemPath() == path)
506             return true;
507         URL itemOriginalURL(URL(), iter->value->originalURL());
508         if (itemOriginalURL.isLocalFile() && itemOriginalURL.fileSystemPath() == path)
509             return true;
510     }
511
512     // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
513     WTFLogAlways("Received an unexpected URL from the web process: '%s'\n", url.string().utf8().data());
514     return false;
515 }
516
517 #if !PLATFORM(COCOA)
518 bool WebProcessProxy::fullKeyboardAccessEnabled()
519 {
520     return false;
521 }
522 #endif
523
524 void WebProcessProxy::addBackForwardItem(uint64_t itemID, uint64_t pageID, const PageState& pageState)
525 {
526     MESSAGE_CHECK_URL(pageState.mainFrameState.originalURLString);
527     MESSAGE_CHECK_URL(pageState.mainFrameState.urlString);
528
529     auto& backForwardListItem = m_backForwardListItemMap.add(itemID, nullptr).iterator->value;
530     if (!backForwardListItem) {
531         BackForwardListItemState backForwardListItemState;
532         backForwardListItemState.identifier = itemID;
533         backForwardListItemState.pageState = pageState;
534         backForwardListItem = WebBackForwardListItem::create(WTFMove(backForwardListItemState), pageID);
535         return;
536     }
537
538     // Update existing item.
539     backForwardListItem->setPageState(pageState);
540 }
541
542 #if ENABLE(NETSCAPE_PLUGIN_API)
543 void WebProcessProxy::getPlugins(bool refresh, Vector<PluginInfo>& plugins, Vector<PluginInfo>& applicationPlugins)
544 {
545     if (refresh)
546         m_processPool->pluginInfoStore().refresh();
547
548     Vector<PluginModuleInfo> pluginModules = m_processPool->pluginInfoStore().plugins();
549     for (size_t i = 0; i < pluginModules.size(); ++i)
550         plugins.append(pluginModules[i].info);
551
552 #if ENABLE(PDFKIT_PLUGIN)
553     // Add built-in PDF last, so that it's not used when a real plug-in is installed.
554     if (!m_processPool->omitPDFSupport()) {
555         plugins.append(PDFPlugin::pluginInfo());
556         applicationPlugins.append(PDFPlugin::pluginInfo());
557     }
558 #else
559     UNUSED_PARAM(applicationPlugins);
560 #endif
561 }
562 #endif // ENABLE(NETSCAPE_PLUGIN_API)
563
564 #if ENABLE(NETSCAPE_PLUGIN_API)
565 void WebProcessProxy::getPluginProcessConnection(uint64_t pluginProcessToken, Ref<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply>&& reply)
566 {
567     PluginProcessManager::singleton().getPluginProcessConnection(pluginProcessToken, WTFMove(reply));
568 }
569 #endif
570
571 void WebProcessProxy::getNetworkProcessConnection(Ref<Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply>&& reply)
572 {
573     m_processPool->getNetworkProcessConnection(WTFMove(reply));
574 }
575
576 void WebProcessProxy::getDatabaseProcessConnection(Ref<Messages::WebProcessProxy::GetDatabaseProcessConnection::DelayedReply>&& reply)
577 {
578     m_processPool->getDatabaseProcessConnection(WTFMove(reply));
579 }
580
581 #if !PLATFORM(COCOA)
582 bool WebProcessProxy::platformIsBeingDebugged() const
583 {
584     return false;
585 }
586 #endif
587
588 void WebProcessProxy::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
589 {
590     if (dispatchMessage(connection, decoder))
591         return;
592
593     if (m_processPool->dispatchMessage(connection, decoder))
594         return;
595
596     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
597         didReceiveWebProcessProxyMessage(connection, decoder);
598         return;
599     }
600
601     // FIXME: Add unhandled message logging.
602 }
603
604 void WebProcessProxy::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& replyEncoder)
605 {
606     if (dispatchSyncMessage(connection, decoder, replyEncoder))
607         return;
608
609     if (m_processPool->dispatchSyncMessage(connection, decoder, replyEncoder))
610         return;
611
612     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
613         didReceiveSyncWebProcessProxyMessage(connection, decoder, replyEncoder);
614         return;
615     }
616
617     // FIXME: Add unhandled message logging.
618 }
619
620 void WebProcessProxy::didClose(IPC::Connection&)
621 {
622     // Protect ourselves, as the call to disconnect() below may otherwise cause us
623     // to be deleted before we can finish our work.
624     Ref<WebProcessProxy> protect(*this);
625
626     webConnection()->didClose();
627
628     Vector<RefPtr<WebPageProxy>> pages;
629     copyValuesToVector(m_pageMap, pages);
630
631     shutDown();
632
633     for (size_t i = 0, size = pages.size(); i < size; ++i)
634         pages[i]->processDidTerminate(ProcessTerminationReason::Crash);
635
636 }
637
638 void WebProcessProxy::didReceiveInvalidMessage(IPC::Connection& connection, IPC::StringReference messageReceiverName, IPC::StringReference messageName)
639 {
640     WTFLogAlways("Received an invalid message \"%s.%s\" from the web process.\n", messageReceiverName.toString().data(), messageName.toString().data());
641
642     WebProcessPool::didReceiveInvalidMessage(messageReceiverName, messageName);
643
644     // Terminate the WebProcess.
645     terminate();
646
647     // Since we've invalidated the connection we'll never get a IPC::Connection::Client::didClose
648     // callback so we'll explicitly call it here instead.
649     didClose(connection);
650 }
651
652 void WebProcessProxy::didBecomeUnresponsive()
653 {
654     m_isResponsive = NoOrMaybe::No;
655
656     Vector<RefPtr<WebPageProxy>> pages;
657     copyValuesToVector(m_pageMap, pages);
658
659     auto isResponsiveCallbacks = WTFMove(m_isResponsiveCallbacks);
660
661     for (auto& page : pages)
662         page->processDidBecomeUnresponsive();
663
664     bool isWebProcessResponsive = false;
665     for (auto& callback : isResponsiveCallbacks)
666         callback(isWebProcessResponsive);
667 }
668
669 void WebProcessProxy::didBecomeResponsive()
670 {
671     m_isResponsive = NoOrMaybe::Maybe;
672
673     Vector<RefPtr<WebPageProxy>> pages;
674     copyValuesToVector(m_pageMap, pages);
675     for (auto& page : pages)
676         page->processDidBecomeResponsive();
677 }
678
679 void WebProcessProxy::willChangeIsResponsive()
680 {
681     Vector<RefPtr<WebPageProxy>> pages;
682     copyValuesToVector(m_pageMap, pages);
683     for (auto& page : pages)
684         page->willChangeProcessIsResponsive();
685 }
686
687 void WebProcessProxy::didChangeIsResponsive()
688 {
689     Vector<RefPtr<WebPageProxy>> pages;
690     copyValuesToVector(m_pageMap, pages);
691     for (auto& page : pages)
692         page->didChangeProcessIsResponsive();
693 }
694
695 bool WebProcessProxy::mayBecomeUnresponsive()
696 {
697     return !platformIsBeingDebugged();
698 }
699
700 void WebProcessProxy::didFinishLaunching(ProcessLauncher* launcher, IPC::Connection::Identifier connectionIdentifier)
701 {
702     ChildProcessProxy::didFinishLaunching(launcher, connectionIdentifier);
703
704     for (WebPageProxy* page : m_pageMap.values()) {
705         ASSERT(this == &page->process());
706         page->processDidFinishLaunching();
707     }
708
709     m_webConnection = WebConnectionToWebProcess::create(this);
710
711     m_processPool->processDidFinishLaunching(this);
712
713 #if PLATFORM(IOS)
714     if (connection()) {
715         if (xpc_connection_t xpcConnection = connection()->xpcConnection())
716             m_throttler.didConnectToProcess(xpc_connection_get_pid(xpcConnection));
717     }
718 #endif
719 }
720
721 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
722 {
723     if (!WebFrameProxyMap::isValidKey(frameID))
724         return 0;
725
726     return m_frameMap.get(frameID);
727 }
728
729 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
730 {
731     return WebFrameProxyMap::isValidKey(frameID) && !m_frameMap.contains(frameID);
732 }
733
734 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
735 {
736     ASSERT(canCreateFrame(frameID));
737     m_frameMap.set(frameID, frameProxy);
738 }
739
740 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
741 {
742     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
743     // back to the UIProcess, then the frameDestroyed message will still be received because it
744     // gets sent directly to the WebProcessProxy.
745     ASSERT(WebFrameProxyMap::isValidKey(frameID));
746     m_frameMap.remove(frameID);
747 }
748
749 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
750 {
751     Vector<RefPtr<WebFrameProxy>> frames;
752     copyValuesToVector(m_frameMap, frames);
753     for (size_t i = 0, size = frames.size(); i < size; ++i) {
754         if (frames[i]->page() == page)
755             frames[i]->webProcessWillShutDown();
756     }
757 }
758
759 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
760 {
761     size_t result = 0;
762     for (HashMap<uint64_t, RefPtr<WebFrameProxy>>::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
763         if (iter->value->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(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(SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, std::chrono::system_clock::time_point 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(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     Vector<RefPtr<WebPageProxy>> pages;
892     copyValuesToVector(m_pageMap, pages);
893
894     shutDown();
895
896     for (size_t i = 0, size = pages.size(); i < size; ++i)
897         pages[i]->processDidTerminate(reason);
898 }
899
900 void WebProcessProxy::stopResponsivenessTimer()
901 {
902     responsivenessTimer().stop();
903 }
904
905 void WebProcessProxy::enableSuddenTermination()
906 {
907     if (state() != State::Running)
908         return;
909
910     ASSERT(m_numberOfTimesSuddenTerminationWasDisabled);
911     WebCore::enableSuddenTermination();
912     --m_numberOfTimesSuddenTerminationWasDisabled;
913 }
914
915 void WebProcessProxy::disableSuddenTermination()
916 {
917     if (state() != State::Running)
918         return;
919
920     WebCore::disableSuddenTermination();
921     ++m_numberOfTimesSuddenTerminationWasDisabled;
922 }
923
924 RefPtr<API::Object> WebProcessProxy::transformHandlesToObjects(API::Object* object)
925 {
926     struct Transformer final : UserData::Transformer {
927         Transformer(WebProcessProxy& webProcessProxy)
928             : m_webProcessProxy(webProcessProxy)
929         {
930         }
931
932         bool shouldTransformObject(const API::Object& object) const override
933         {
934             switch (object.type()) {
935             case API::Object::Type::FrameHandle:
936                 return static_cast<const API::FrameHandle&>(object).isAutoconverting();
937
938             case API::Object::Type::PageHandle:
939                 return static_cast<const API::PageHandle&>(object).isAutoconverting();
940
941             case API::Object::Type::PageGroupHandle:
942 #if PLATFORM(COCOA)
943             case API::Object::Type::ObjCObjectGraph:
944 #endif
945                 return true;
946
947             default:
948                 return false;
949             }
950         }
951
952         RefPtr<API::Object> transformObject(API::Object& object) const override
953         {
954             switch (object.type()) {
955             case API::Object::Type::FrameHandle:
956                 ASSERT(static_cast<API::FrameHandle&>(object).isAutoconverting());
957                 return m_webProcessProxy.webFrame(static_cast<API::FrameHandle&>(object).frameID());
958
959             case API::Object::Type::PageGroupHandle:
960                 return WebPageGroup::get(static_cast<API::PageGroupHandle&>(object).webPageGroupData().pageGroupID);
961
962             case API::Object::Type::PageHandle:
963                 ASSERT(static_cast<API::PageHandle&>(object).isAutoconverting());
964                 return m_webProcessProxy.webPage(static_cast<API::PageHandle&>(object).pageID());
965
966 #if PLATFORM(COCOA)
967             case API::Object::Type::ObjCObjectGraph:
968                 return m_webProcessProxy.transformHandlesToObjects(static_cast<ObjCObjectGraph&>(object));
969 #endif
970             default:
971                 return &object;
972             }
973         }
974
975         WebProcessProxy& m_webProcessProxy;
976     };
977
978     return UserData::transform(object, Transformer(*this));
979 }
980
981 RefPtr<API::Object> WebProcessProxy::transformObjectsToHandles(API::Object* object)
982 {
983     struct Transformer final : UserData::Transformer {
984         bool shouldTransformObject(const API::Object& object) const override
985         {
986             switch (object.type()) {
987             case API::Object::Type::Frame:
988             case API::Object::Type::Page:
989             case API::Object::Type::PageGroup:
990 #if PLATFORM(COCOA)
991             case API::Object::Type::ObjCObjectGraph:
992 #endif
993                 return true;
994
995             default:
996                 return false;
997             }
998         }
999
1000         RefPtr<API::Object> transformObject(API::Object& object) const override
1001         {
1002             switch (object.type()) {
1003             case API::Object::Type::Frame:
1004                 return API::FrameHandle::createAutoconverting(static_cast<const WebFrameProxy&>(object).frameID());
1005
1006             case API::Object::Type::Page:
1007                 return API::PageHandle::createAutoconverting(static_cast<const WebPageProxy&>(object).pageID());
1008
1009             case API::Object::Type::PageGroup:
1010                 return API::PageGroupHandle::create(WebPageGroupData(static_cast<const WebPageGroup&>(object).data()));
1011
1012 #if PLATFORM(COCOA)
1013             case API::Object::Type::ObjCObjectGraph:
1014                 return transformObjectsToHandles(static_cast<ObjCObjectGraph&>(object));
1015 #endif
1016
1017             default:
1018                 return &object;
1019             }
1020         }
1021     };
1022
1023     return UserData::transform(object, Transformer());
1024 }
1025
1026 void WebProcessProxy::sendProcessWillSuspendImminently()
1027 {
1028     if (!canSendMessage())
1029         return;
1030
1031     bool handled = false;
1032     sendSync(Messages::WebProcess::ProcessWillSuspendImminently(), Messages::WebProcess::ProcessWillSuspendImminently::Reply(handled), 0, 1_s);
1033 }
1034
1035 void WebProcessProxy::sendPrepareToSuspend()
1036 {
1037     if (canSendMessage())
1038         send(Messages::WebProcess::PrepareToSuspend(), 0);
1039 }
1040
1041 void WebProcessProxy::sendCancelPrepareToSuspend()
1042 {
1043     if (canSendMessage())
1044         send(Messages::WebProcess::CancelPrepareToSuspend(), 0);
1045 }
1046
1047 void WebProcessProxy::sendProcessDidResume()
1048 {
1049     if (canSendMessage())
1050         send(Messages::WebProcess::ProcessDidResume(), 0);
1051 }
1052
1053 void WebProcessProxy::processReadyToSuspend()
1054 {
1055     m_throttler.processReadyToSuspend();
1056 }
1057
1058 void WebProcessProxy::didCancelProcessSuspension()
1059 {
1060     m_throttler.didCancelProcessSuspension();
1061 }
1062
1063 void WebProcessProxy::reinstateNetworkProcessAssertionState(NetworkProcessProxy& newNetworkProcessProxy)
1064 {
1065 #if PLATFORM(IOS)
1066     ASSERT(!m_backgroundTokenForNetworkProcess || !m_foregroundTokenForNetworkProcess);
1067
1068     // The network process crashed; take new tokens for the new network process.
1069     if (m_backgroundTokenForNetworkProcess)
1070         m_backgroundTokenForNetworkProcess = newNetworkProcessProxy.throttler().backgroundActivityToken();
1071     else if (m_foregroundTokenForNetworkProcess)
1072         m_foregroundTokenForNetworkProcess = newNetworkProcessProxy.throttler().foregroundActivityToken();
1073 #else
1074     UNUSED_PARAM(newNetworkProcessProxy);
1075 #endif
1076 }
1077
1078 void WebProcessProxy::didSetAssertionState(AssertionState state)
1079 {
1080 #if PLATFORM(IOS)
1081     ASSERT(!m_backgroundTokenForNetworkProcess || !m_foregroundTokenForNetworkProcess);
1082
1083     switch (state) {
1084     case AssertionState::Suspended:
1085         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Suspended) release all assertions for network process", this);
1086         m_foregroundTokenForNetworkProcess = nullptr;
1087         m_backgroundTokenForNetworkProcess = nullptr;
1088         for (auto& page : m_pageMap.values())
1089             page->processWillBecomeSuspended();
1090         break;
1091
1092     case AssertionState::Background:
1093         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Background) taking background assertion for network process", this);
1094         m_backgroundTokenForNetworkProcess = processPool().ensureNetworkProcess().throttler().backgroundActivityToken();
1095         m_foregroundTokenForNetworkProcess = nullptr;
1096         break;
1097     
1098     case AssertionState::Foreground:
1099         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Foreground) taking foreground assertion for network process", this);
1100         m_foregroundTokenForNetworkProcess = processPool().ensureNetworkProcess().throttler().foregroundActivityToken();
1101         m_backgroundTokenForNetworkProcess = nullptr;
1102         for (auto& page : m_pageMap.values())
1103             page->processWillBecomeForeground();
1104         break;
1105     }
1106
1107     ASSERT(!m_backgroundTokenForNetworkProcess || !m_foregroundTokenForNetworkProcess);
1108 #else
1109     UNUSED_PARAM(state);
1110 #endif
1111 }
1112     
1113 void WebProcessProxy::setIsHoldingLockedFiles(bool isHoldingLockedFiles)
1114 {
1115     if (!isHoldingLockedFiles) {
1116         RELEASE_LOG(ProcessSuspension, "UIProcess is releasing a background assertion because the WebContent process is no longer holding locked files");
1117         m_tokenForHoldingLockedFiles = nullptr;
1118         return;
1119     }
1120     if (!m_tokenForHoldingLockedFiles) {
1121         RELEASE_LOG(ProcessSuspension, "UIProcess is taking a background assertion because the WebContent process is holding locked files");
1122         m_tokenForHoldingLockedFiles = m_throttler.backgroundActivityToken();
1123     }
1124 }
1125
1126 void WebProcessProxy::isResponsive(WTF::Function<void(bool isWebProcessResponsive)>&& callback)
1127 {
1128     if (m_isResponsive == NoOrMaybe::No) {
1129         if (callback) {
1130             RunLoop::main().dispatch([callback = WTFMove(callback)] {
1131                 bool isWebProcessResponsive = false;
1132                 callback(isWebProcessResponsive);
1133             });
1134         }
1135         return;
1136     }
1137
1138     if (callback)
1139         m_isResponsiveCallbacks.append(WTFMove(callback));
1140
1141     responsivenessTimer().start();
1142     send(Messages::WebProcess::MainThreadPing(), 0);
1143 }
1144
1145 void WebProcessProxy::didReceiveMainThreadPing()
1146 {
1147     responsivenessTimer().stop();
1148
1149     auto isResponsiveCallbacks = WTFMove(m_isResponsiveCallbacks);
1150     bool isWebProcessResponsive = true;
1151     for (auto& callback : isResponsiveCallbacks)
1152         callback(isWebProcessResponsive);
1153 }
1154
1155 void WebProcessProxy::didReceiveBackgroundResponsivenessPing()
1156 {
1157     m_backgroundResponsivenessTimer.didReceiveBackgroundResponsivenessPong();
1158 }
1159
1160 void WebProcessProxy::processTerminated()
1161 {
1162     m_responsivenessTimer.processTerminated();
1163     m_backgroundResponsivenessTimer.processTerminated();
1164 }
1165
1166 void WebProcessProxy::logDiagnosticMessageForResourceLimitTermination(const String& limitKey)
1167 {
1168     if (pageCount())
1169         (*pages().begin())->logDiagnosticMessage(DiagnosticLoggingKeys::simulatedPageCrashKey(), limitKey, ShouldSample::No);
1170 }
1171
1172 void WebProcessProxy::didExceedInactiveMemoryLimitWhileActive()
1173 {
1174     for (auto& page : pages())
1175         page->didExceedInactiveMemoryLimitWhileActive();
1176 }
1177
1178 void WebProcessProxy::didExceedActiveMemoryLimit()
1179 {
1180     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedActiveMemoryLimit() Terminating WebProcess with pid %d that has exceeded the active memory limit", this, processIdentifier());
1181     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededActiveMemoryLimitKey());
1182     requestTermination(ProcessTerminationReason::ExceededMemoryLimit);
1183 }
1184
1185 void WebProcessProxy::didExceedInactiveMemoryLimit()
1186 {
1187     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedInactiveMemoryLimit() Terminating WebProcess with pid %d that has exceeded the inactive memory limit", this, processIdentifier());
1188     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededInactiveMemoryLimitKey());
1189     requestTermination(ProcessTerminationReason::ExceededMemoryLimit);
1190 }
1191
1192 void WebProcessProxy::didExceedCPULimit()
1193 {
1194     for (auto& page : pages()) {
1195         if (page->isPlayingAudio()) {
1196             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());
1197             return;
1198         }
1199
1200         if (page->hasActiveAudioStream() || page->hasActiveVideoStream()) {
1201             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());
1202             return;
1203         }
1204     }
1205
1206     bool hasVisiblePage = false;
1207     for (auto& page : pages()) {
1208         if (page->isViewVisible()) {
1209             page->didExceedBackgroundCPULimitWhileInForeground();
1210             hasVisiblePage = true;
1211         }
1212     }
1213
1214     // We only notify the client that the process exceeded the CPU limit when it is visible, we do not terminate it.
1215     if (hasVisiblePage)
1216         return;
1217
1218     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedCPULimit() Terminating background WebProcess with pid %d that has exceeded the background CPU limit", this, processIdentifier());
1219     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededBackgroundCPULimitKey());
1220     requestTermination(ProcessTerminationReason::ExceededCPULimit);
1221 }
1222
1223 void WebProcessProxy::updateBackgroundResponsivenessTimer()
1224 {
1225     m_backgroundResponsivenessTimer.updateState();
1226 }
1227
1228 #if !PLATFORM(COCOA)
1229 const HashSet<String>& WebProcessProxy::platformPathsWithAssumedReadAccess()
1230 {
1231     static NeverDestroyed<HashSet<String>> platformPathsWithAssumedReadAccess;
1232     return platformPathsWithAssumedReadAccess;
1233 }
1234 #endif
1235
1236 } // namespace WebKit