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