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