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