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