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