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