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