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