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