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