Unreviewed, rolling out r243008.
[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 #endif
763 }
764
765 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
766 {
767     if (!WebFrameProxyMap::isValidKey(frameID))
768         return 0;
769
770     return m_frameMap.get(frameID);
771 }
772
773 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
774 {
775     return WebFrameProxyMap::isValidKey(frameID) && !m_frameMap.contains(frameID);
776 }
777
778 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy& frameProxy)
779 {
780     m_frameMap.set(frameID, &frameProxy);
781 }
782
783 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
784 {
785     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
786     // back to the UIProcess, then the frameDestroyed message will still be received because it
787     // gets sent directly to the WebProcessProxy.
788     ASSERT(WebFrameProxyMap::isValidKey(frameID));
789     m_frameMap.remove(frameID);
790 }
791
792 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
793 {
794     for (auto& frame : copyToVector(m_frameMap.values())) {
795         if (frame->page() == page)
796             frame->webProcessWillShutDown();
797     }
798 }
799
800 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
801 {
802     size_t result = 0;
803     for (auto& frame : m_frameMap.values()) {
804         if (frame->page() == page)
805             ++result;
806     }
807     return result;
808 }
809
810 auto WebProcessProxy::visiblePageToken() const -> VisibleWebPageToken
811 {
812     return m_visiblePageCounter.count();
813 }
814
815 RefPtr<API::UserInitiatedAction> WebProcessProxy::userInitiatedActivity(uint64_t identifier)
816 {
817     if (!UserInitiatedActionMap::isValidKey(identifier) || !identifier)
818         return nullptr;
819
820     auto result = m_userInitiatedActionMap.ensure(identifier, [] { return API::UserInitiatedAction::create(); });
821     return result.iterator->value;
822 }
823
824 bool WebProcessProxy::isResponsive() const
825 {
826     return m_responsivenessTimer.isResponsive() && m_backgroundResponsivenessTimer.isResponsive();
827 }
828
829 void WebProcessProxy::didDestroyUserGestureToken(uint64_t identifier)
830 {
831     ASSERT(UserInitiatedActionMap::isValidKey(identifier));
832     m_userInitiatedActionMap.remove(identifier);
833 }
834
835 bool WebProcessProxy::canBeAddedToWebProcessCache() const
836 {
837     if (isServiceWorkerProcess())
838         return false;
839
840     if (WebKit::isInspectorProcessPool(processPool()))
841         return false;
842
843     return true;
844 }
845
846 void WebProcessProxy::maybeShutDown(AllowProcessCaching allowProcessCaching)
847 {
848     if (state() == State::Terminated || !canTerminateAuxiliaryProcess())
849         return;
850
851     if (allowProcessCaching == AllowProcessCaching::Yes && canBeAddedToWebProcessCache() && processPool().webProcessCache().addProcessIfPossible(*this))
852         return;
853
854     shutDown();
855 }
856
857 bool WebProcessProxy::canTerminateAuxiliaryProcess()
858 {
859     if (!m_pageMap.isEmpty() || m_suspendedPageCount || !m_provisionalPages.isEmpty() || m_isInProcessCache)
860         return false;
861
862     if (!m_processPool->shouldTerminate(this))
863         return false;
864
865     return true;
866 }
867
868 void WebProcessProxy::shouldTerminate(CompletionHandler<void(bool)>&& completionHandler)
869 {
870     bool shouldTerminate = canTerminateAuxiliaryProcess();
871     if (shouldTerminate) {
872         // We know that the web process is going to terminate so start shutting it down in the UI process.
873         shutDown();
874     }
875     completionHandler(shouldTerminate);
876 }
877
878 void WebProcessProxy::updateTextCheckerState()
879 {
880     if (canSendMessage())
881         send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
882 }
883
884 void WebProcessProxy::didSaveToPageCache()
885 {
886     m_processPool->processDidCachePage(this);
887 }
888
889 void WebProcessProxy::releasePageCache()
890 {
891     if (canSendMessage())
892         send(Messages::WebProcess::ReleasePageCache(), 0);
893 }
894
895 void WebProcessProxy::windowServerConnectionStateChanged()
896 {
897     for (const auto& page : m_pageMap.values())
898         page->activityStateDidChange(ActivityState::IsVisuallyIdle);
899 }
900
901 void WebProcessProxy::fetchWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, CompletionHandler<void(WebsiteData)>&& completionHandler)
902 {
903     ASSERT(canSendMessage());
904
905     auto token = throttler().backgroundActivityToken();
906     RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because the Web process is fetching Website data", this);
907
908     connection()->sendWithReply(Messages::WebProcess::FetchWebsiteData(sessionID, dataTypes), 0, RunLoop::main(), [this, token, completionHandler = WTFMove(completionHandler), sessionID] (auto reply) mutable {
909 #if RELEASE_LOG_DISABLED
910         UNUSED_PARAM(sessionID);
911         UNUSED_PARAM(this);
912 #endif
913         if (!reply) {
914             completionHandler(WebsiteData { });
915             return;
916         }
917
918         completionHandler(WTFMove(std::get<0>(*reply)));
919         RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is releasing a background assertion because the Web process is done fetching Website data", this);
920     });
921 }
922
923 void WebProcessProxy::deleteWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, WallTime modifiedSince, CompletionHandler<void()>&& completionHandler)
924 {
925     ASSERT(canSendMessage());
926
927     auto token = throttler().backgroundActivityToken();
928     RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because the Web process is deleting Website data", this);
929
930     connection()->sendWithReply(Messages::WebProcess::DeleteWebsiteData(sessionID, dataTypes, modifiedSince), 0, RunLoop::main(), [this, token, completionHandler = WTFMove(completionHandler), sessionID] (auto reply) mutable {
931 #if RELEASE_LOG_DISABLED
932         UNUSED_PARAM(this);
933         UNUSED_PARAM(sessionID);
934 #endif
935         completionHandler();
936         RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is releasing a background assertion because the Web process is done deleting Website data", this);
937     });
938 }
939
940 void WebProcessProxy::deleteWebsiteDataForOrigins(PAL::SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, const Vector<WebCore::SecurityOriginData>& origins, CompletionHandler<void()>&& completionHandler)
941 {
942     ASSERT(canSendMessage());
943
944     auto token = throttler().backgroundActivityToken();
945     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);
946
947     connection()->sendWithReply(Messages::WebProcess::DeleteWebsiteDataForOrigins(sessionID, dataTypes, origins), 0, RunLoop::main(), [this, token, completionHandler = WTFMove(completionHandler), sessionID] (auto reply) mutable {
948 #if RELEASE_LOG_DISABLED
949         UNUSED_PARAM(this);
950         UNUSED_PARAM(sessionID);
951 #endif
952         completionHandler();
953         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);
954     });
955 }
956
957 void WebProcessProxy::requestTermination(ProcessTerminationReason reason)
958 {
959     if (state() == State::Terminated)
960         return;
961
962     auto protectedThis = makeRef(*this);
963     RELEASE_LOG_IF(m_websiteDataStore->sessionID().isAlwaysOnLoggingAllowed(), Process, "%p - WebProcessProxy::requestTermination - reason %d", this, reason);
964
965     AuxiliaryProcessProxy::terminate();
966
967     if (webConnection())
968         webConnection()->didClose();
969
970     auto pages = copyToVectorOf<RefPtr<WebPageProxy>>(m_pageMap.values());
971
972     shutDown();
973
974     for (auto& page : pages)
975         page->processDidTerminate(reason);
976 }
977
978 void WebProcessProxy::stopResponsivenessTimer()
979 {
980     responsivenessTimer().stop();
981 }
982
983 void WebProcessProxy::enableSuddenTermination()
984 {
985     if (state() != State::Running)
986         return;
987
988     ASSERT(m_numberOfTimesSuddenTerminationWasDisabled);
989     WebCore::enableSuddenTermination();
990     --m_numberOfTimesSuddenTerminationWasDisabled;
991 }
992
993 void WebProcessProxy::disableSuddenTermination()
994 {
995     if (state() != State::Running)
996         return;
997
998     WebCore::disableSuddenTermination();
999     ++m_numberOfTimesSuddenTerminationWasDisabled;
1000 }
1001
1002 RefPtr<API::Object> WebProcessProxy::transformHandlesToObjects(API::Object* object)
1003 {
1004     struct Transformer final : UserData::Transformer {
1005         Transformer(WebProcessProxy& webProcessProxy)
1006             : m_webProcessProxy(webProcessProxy)
1007         {
1008         }
1009
1010         bool shouldTransformObject(const API::Object& object) const override
1011         {
1012             switch (object.type()) {
1013             case API::Object::Type::FrameHandle:
1014                 return static_cast<const API::FrameHandle&>(object).isAutoconverting();
1015
1016             case API::Object::Type::PageHandle:
1017                 return static_cast<const API::PageHandle&>(object).isAutoconverting();
1018
1019             case API::Object::Type::PageGroupHandle:
1020 #if PLATFORM(COCOA)
1021             case API::Object::Type::ObjCObjectGraph:
1022 #endif
1023                 return true;
1024
1025             default:
1026                 return false;
1027             }
1028         }
1029
1030         RefPtr<API::Object> transformObject(API::Object& object) const override
1031         {
1032             switch (object.type()) {
1033             case API::Object::Type::FrameHandle:
1034                 ASSERT(static_cast<API::FrameHandle&>(object).isAutoconverting());
1035                 return m_webProcessProxy.webFrame(static_cast<API::FrameHandle&>(object).frameID());
1036
1037             case API::Object::Type::PageGroupHandle:
1038                 return WebPageGroup::get(static_cast<API::PageGroupHandle&>(object).webPageGroupData().pageGroupID);
1039
1040             case API::Object::Type::PageHandle:
1041                 ASSERT(static_cast<API::PageHandle&>(object).isAutoconverting());
1042                 return m_webProcessProxy.webPage(static_cast<API::PageHandle&>(object).pageID());
1043
1044 #if PLATFORM(COCOA)
1045             case API::Object::Type::ObjCObjectGraph:
1046                 return m_webProcessProxy.transformHandlesToObjects(static_cast<ObjCObjectGraph&>(object));
1047 #endif
1048             default:
1049                 return &object;
1050             }
1051         }
1052
1053         WebProcessProxy& m_webProcessProxy;
1054     };
1055
1056     return UserData::transform(object, Transformer(*this));
1057 }
1058
1059 RefPtr<API::Object> WebProcessProxy::transformObjectsToHandles(API::Object* object)
1060 {
1061     struct Transformer final : UserData::Transformer {
1062         bool shouldTransformObject(const API::Object& object) const override
1063         {
1064             switch (object.type()) {
1065             case API::Object::Type::Frame:
1066             case API::Object::Type::Page:
1067             case API::Object::Type::PageGroup:
1068 #if PLATFORM(COCOA)
1069             case API::Object::Type::ObjCObjectGraph:
1070 #endif
1071                 return true;
1072
1073             default:
1074                 return false;
1075             }
1076         }
1077
1078         RefPtr<API::Object> transformObject(API::Object& object) const override
1079         {
1080             switch (object.type()) {
1081             case API::Object::Type::Frame:
1082                 return API::FrameHandle::createAutoconverting(static_cast<const WebFrameProxy&>(object).frameID());
1083
1084             case API::Object::Type::Page:
1085                 return API::PageHandle::createAutoconverting(static_cast<const WebPageProxy&>(object).pageID());
1086
1087             case API::Object::Type::PageGroup:
1088                 return API::PageGroupHandle::create(WebPageGroupData(static_cast<const WebPageGroup&>(object).data()));
1089
1090 #if PLATFORM(COCOA)
1091             case API::Object::Type::ObjCObjectGraph:
1092                 return transformObjectsToHandles(static_cast<ObjCObjectGraph&>(object));
1093 #endif
1094
1095             default:
1096                 return &object;
1097             }
1098         }
1099     };
1100
1101     return UserData::transform(object, Transformer());
1102 }
1103
1104 void WebProcessProxy::sendProcessWillSuspendImminently()
1105 {
1106     if (!canSendMessage())
1107         return;
1108
1109     bool handled = false;
1110     sendSync(Messages::WebProcess::ProcessWillSuspendImminently(), Messages::WebProcess::ProcessWillSuspendImminently::Reply(handled), 0, 1_s);
1111 }
1112
1113 void WebProcessProxy::sendPrepareToSuspend()
1114 {
1115     if (canSendMessage())
1116         send(Messages::WebProcess::PrepareToSuspend(), 0);
1117 }
1118
1119 void WebProcessProxy::sendCancelPrepareToSuspend()
1120 {
1121     if (canSendMessage())
1122         send(Messages::WebProcess::CancelPrepareToSuspend(), 0);
1123 }
1124
1125 void WebProcessProxy::sendProcessDidResume()
1126 {
1127     if (canSendMessage())
1128         send(Messages::WebProcess::ProcessDidResume(), 0);
1129 }
1130
1131 void WebProcessProxy::processReadyToSuspend()
1132 {
1133     m_throttler.processReadyToSuspend();
1134 }
1135
1136 void WebProcessProxy::didCancelProcessSuspension()
1137 {
1138     m_throttler.didCancelProcessSuspension();
1139 }
1140
1141 void WebProcessProxy::didSetAssertionState(AssertionState state)
1142 {
1143 #if PLATFORM(IOS_FAMILY)
1144     if (isServiceWorkerProcess())
1145         return;
1146
1147     ASSERT(!m_backgroundToken || !m_foregroundToken);
1148
1149     switch (state) {
1150     case AssertionState::Suspended:
1151         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Suspended) release all assertions for network process", this);
1152         m_foregroundToken = nullptr;
1153         m_backgroundToken = nullptr;
1154         for (auto& page : m_pageMap.values())
1155             page->processWillBecomeSuspended();
1156         break;
1157
1158     case AssertionState::Background:
1159         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Background) taking background assertion for network process", this);
1160         m_backgroundToken = processPool().backgroundWebProcessToken();
1161         m_foregroundToken = nullptr;
1162         break;
1163     
1164     case AssertionState::Foreground:
1165         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Foreground) taking foreground assertion for network process", this);
1166         m_foregroundToken = processPool().foregroundWebProcessToken();
1167         m_backgroundToken = nullptr;
1168         for (auto& page : m_pageMap.values())
1169             page->processWillBecomeForeground();
1170         break;
1171     
1172     case AssertionState::UnboundedNetworking:
1173         ASSERT_NOT_REACHED();
1174     }
1175
1176     ASSERT(!m_backgroundToken || !m_foregroundToken);
1177 #else
1178     UNUSED_PARAM(state);
1179 #endif
1180 }
1181     
1182 void WebProcessProxy::setIsHoldingLockedFiles(bool isHoldingLockedFiles)
1183 {
1184     if (!isHoldingLockedFiles) {
1185         RELEASE_LOG(ProcessSuspension, "UIProcess is releasing a background assertion because the WebContent process is no longer holding locked files");
1186         m_tokenForHoldingLockedFiles = nullptr;
1187         return;
1188     }
1189     if (!m_tokenForHoldingLockedFiles) {
1190         RELEASE_LOG(ProcessSuspension, "UIProcess is taking a background assertion because the WebContent process is holding locked files");
1191         m_tokenForHoldingLockedFiles = m_throttler.backgroundActivityToken();
1192     }
1193 }
1194
1195 void WebProcessProxy::isResponsive(CompletionHandler<void(bool isWebProcessResponsive)>&& callback)
1196 {
1197     if (m_isResponsive == NoOrMaybe::No) {
1198         if (callback) {
1199             RunLoop::main().dispatch([callback = WTFMove(callback)]() mutable {
1200                 bool isWebProcessResponsive = false;
1201                 callback(isWebProcessResponsive);
1202             });
1203         }
1204         return;
1205     }
1206
1207     if (callback)
1208         m_isResponsiveCallbacks.append(WTFMove(callback));
1209
1210     responsivenessTimer().start();
1211     send(Messages::WebProcess::MainThreadPing(), 0);
1212 }
1213
1214 void WebProcessProxy::isResponsiveWithLazyStop()
1215 {
1216     if (m_isResponsive == NoOrMaybe::No)
1217         return;
1218
1219     if (!responsivenessTimer().hasActiveTimer()) {
1220         // We do not send a ping if we are already waiting for the WebProcess.
1221         // Spamming pings on a slow web process is not helpful.
1222         responsivenessTimer().startWithLazyStop();
1223         send(Messages::WebProcess::MainThreadPing(), 0);
1224     }
1225 }
1226
1227 bool WebProcessProxy::isJITEnabled() const
1228 {
1229     return processPool().configuration().isJITEnabled();
1230 }
1231
1232 void WebProcessProxy::didReceiveMainThreadPing()
1233 {
1234     responsivenessTimer().stop();
1235
1236     auto isResponsiveCallbacks = WTFMove(m_isResponsiveCallbacks);
1237     bool isWebProcessResponsive = true;
1238     for (auto& callback : isResponsiveCallbacks)
1239         callback(isWebProcessResponsive);
1240 }
1241
1242 void WebProcessProxy::didReceiveBackgroundResponsivenessPing()
1243 {
1244     m_backgroundResponsivenessTimer.didReceiveBackgroundResponsivenessPong();
1245 }
1246
1247 void WebProcessProxy::processTerminated()
1248 {
1249     m_responsivenessTimer.processTerminated();
1250     m_backgroundResponsivenessTimer.processTerminated();
1251 }
1252
1253 void WebProcessProxy::logDiagnosticMessageForResourceLimitTermination(const String& limitKey)
1254 {
1255     if (pageCount())
1256         (*pages().begin())->logDiagnosticMessage(DiagnosticLoggingKeys::simulatedPageCrashKey(), limitKey, ShouldSample::No);
1257 }
1258
1259 void WebProcessProxy::didExceedInactiveMemoryLimitWhileActive()
1260 {
1261     for (auto& page : pages())
1262         page->didExceedInactiveMemoryLimitWhileActive();
1263 }
1264
1265 void WebProcessProxy::didExceedActiveMemoryLimit()
1266 {
1267     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedActiveMemoryLimit() Terminating WebProcess with pid %d that has exceeded the active memory limit", this, processIdentifier());
1268     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededActiveMemoryLimitKey());
1269     requestTermination(ProcessTerminationReason::ExceededMemoryLimit);
1270 }
1271
1272 void WebProcessProxy::didExceedInactiveMemoryLimit()
1273 {
1274     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedInactiveMemoryLimit() Terminating WebProcess with pid %d that has exceeded the inactive memory limit", this, processIdentifier());
1275     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededInactiveMemoryLimitKey());
1276     requestTermination(ProcessTerminationReason::ExceededMemoryLimit);
1277 }
1278
1279 void WebProcessProxy::didExceedCPULimit()
1280 {
1281     for (auto& page : pages()) {
1282         if (page->isPlayingAudio()) {
1283             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());
1284             return;
1285         }
1286
1287         if (page->hasActiveAudioStream() || page->hasActiveVideoStream()) {
1288             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());
1289             return;
1290         }
1291     }
1292
1293     bool hasVisiblePage = false;
1294     for (auto& page : pages()) {
1295         if (page->isViewVisible()) {
1296             page->didExceedBackgroundCPULimitWhileInForeground();
1297             hasVisiblePage = true;
1298         }
1299     }
1300
1301     // We only notify the client that the process exceeded the CPU limit when it is visible, we do not terminate it.
1302     if (hasVisiblePage)
1303         return;
1304
1305     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedCPULimit() Terminating background WebProcess with pid %d that has exceeded the background CPU limit", this, processIdentifier());
1306     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededBackgroundCPULimitKey());
1307     requestTermination(ProcessTerminationReason::ExceededCPULimit);
1308 }
1309
1310 void WebProcessProxy::updateBackgroundResponsivenessTimer()
1311 {
1312     m_backgroundResponsivenessTimer.updateState();
1313 }
1314
1315 #if !PLATFORM(COCOA)
1316 const HashSet<String>& WebProcessProxy::platformPathsWithAssumedReadAccess()
1317 {
1318     static NeverDestroyed<HashSet<String>> platformPathsWithAssumedReadAccess;
1319     return platformPathsWithAssumedReadAccess;
1320 }
1321 #endif
1322
1323 void WebProcessProxy::createNewMessagePortChannel(const MessagePortIdentifier& port1, const MessagePortIdentifier& port2)
1324 {
1325     m_processEntangledPorts.add(port1);
1326     m_processEntangledPorts.add(port2);
1327     UIMessagePortChannelProvider::singleton().registry().didCreateMessagePortChannel(port1, port2);
1328 }
1329
1330 void WebProcessProxy::entangleLocalPortInThisProcessToRemote(const MessagePortIdentifier& local, const MessagePortIdentifier& remote)
1331 {
1332     m_processEntangledPorts.add(local);
1333     UIMessagePortChannelProvider::singleton().registry().didEntangleLocalToRemote(local, remote, coreProcessIdentifier());
1334
1335     auto* channel = UIMessagePortChannelProvider::singleton().registry().existingChannelContainingPort(local);
1336     if (channel && channel->hasAnyMessagesPendingOrInFlight())
1337         send(Messages::WebProcess::MessagesAvailableForPort(local), 0);
1338 }
1339
1340 void WebProcessProxy::messagePortDisentangled(const MessagePortIdentifier& port)
1341 {
1342     auto result = m_processEntangledPorts.remove(port);
1343     ASSERT_UNUSED(result, result);
1344
1345     UIMessagePortChannelProvider::singleton().registry().didDisentangleMessagePort(port);
1346 }
1347
1348 void WebProcessProxy::messagePortClosed(const MessagePortIdentifier& port)
1349 {
1350     UIMessagePortChannelProvider::singleton().registry().didCloseMessagePort(port);
1351 }
1352
1353 void WebProcessProxy::takeAllMessagesForPort(const MessagePortIdentifier& port, uint64_t messagesCallbackIdentifier)
1354 {
1355     UIMessagePortChannelProvider::singleton().registry().takeAllMessagesForPort(port, [this, protectedThis = makeRef(*this), messagesCallbackIdentifier](Vector<MessageWithMessagePorts>&& messages, Function<void()>&& deliveryCallback) {
1356
1357         static uint64_t currentMessageBatchIdentifier;
1358         auto result = m_messageBatchDeliveryCompletionHandlers.ensure(++currentMessageBatchIdentifier, [deliveryCallback = WTFMove(deliveryCallback)]() mutable {
1359             return WTFMove(deliveryCallback);
1360         });
1361         ASSERT_UNUSED(result, result.isNewEntry);
1362
1363         send(Messages::WebProcess::DidTakeAllMessagesForPort(WTFMove(messages), messagesCallbackIdentifier, currentMessageBatchIdentifier), 0);
1364     });
1365 }
1366
1367 void WebProcessProxy::didDeliverMessagePortMessages(uint64_t messageBatchIdentifier)
1368 {
1369     auto callback = m_messageBatchDeliveryCompletionHandlers.take(messageBatchIdentifier);
1370     ASSERT(callback);
1371     callback();
1372 }
1373
1374 void WebProcessProxy::postMessageToRemote(MessageWithMessagePorts&& message, const MessagePortIdentifier& port)
1375 {
1376     if (UIMessagePortChannelProvider::singleton().registry().didPostMessageToRemote(WTFMove(message), port)) {
1377         // Look up the process for that port
1378         auto* channel = UIMessagePortChannelProvider::singleton().registry().existingChannelContainingPort(port);
1379         ASSERT(channel);
1380         auto processIdentifier = channel->processForPort(port);
1381         if (processIdentifier) {
1382             if (auto* process = WebProcessProxy::processForIdentifier(*processIdentifier))
1383                 process->send(Messages::WebProcess::MessagesAvailableForPort(port), 0);
1384         }
1385     }
1386 }
1387
1388 void WebProcessProxy::checkRemotePortForActivity(const WebCore::MessagePortIdentifier port, uint64_t callbackIdentifier)
1389 {
1390     UIMessagePortChannelProvider::singleton().registry().checkRemotePortForActivity(port, [this, protectedThis = makeRef(*this), callbackIdentifier](MessagePortChannelProvider::HasActivity hasActivity) {
1391         send(Messages::WebProcess::DidCheckRemotePortForActivity(callbackIdentifier, hasActivity == MessagePortChannelProvider::HasActivity::Yes), 0);
1392     });
1393 }
1394
1395 void WebProcessProxy::checkProcessLocalPortForActivity(const MessagePortIdentifier& port, CompletionHandler<void(MessagePortChannelProvider::HasActivity)>&& callback)
1396 {
1397     static uint64_t currentCallbackIdentifier;
1398     auto result = m_localPortActivityCompletionHandlers.ensure(++currentCallbackIdentifier, [callback = WTFMove(callback)]() mutable {
1399         return WTFMove(callback);
1400     });
1401     ASSERT_UNUSED(result, result.isNewEntry);
1402
1403     send(Messages::WebProcess::CheckProcessLocalPortForActivity(port, currentCallbackIdentifier), 0);
1404 }
1405
1406 void WebProcessProxy::didCheckProcessLocalPortForActivity(uint64_t callbackIdentifier, bool isLocallyReachable)
1407 {
1408     auto callback = m_localPortActivityCompletionHandlers.take(callbackIdentifier);
1409     if (!callback)
1410         return;
1411
1412     callback(isLocallyReachable ? MessagePortChannelProvider::HasActivity::Yes : MessagePortChannelProvider::HasActivity::No);
1413 }
1414
1415 void WebProcessProxy::didCollectPrewarmInformation(const WebCore::RegistrableDomain& domain, const WebCore::PrewarmInformation& prewarmInformation)
1416 {
1417     processPool().didCollectPrewarmInformation(domain, prewarmInformation);
1418 }
1419
1420 void WebProcessProxy::activePagesDomainsForTesting(CompletionHandler<void(Vector<String>&&)>&& completionHandler)
1421 {
1422     connection()->sendWithAsyncReply(Messages::WebProcess::GetActivePagesOriginsForTesting(), WTFMove(completionHandler));
1423 }
1424
1425 void WebProcessProxy::didStartProvisionalLoadForMainFrame(const URL& url)
1426 {
1427     RELEASE_ASSERT(!isInProcessCache());
1428
1429     // This process has been used for several registrable domains already.
1430     if (m_registrableDomain && m_registrableDomain->isEmpty())
1431         return;
1432
1433     auto registrableDomain = WebCore::RegistrableDomain { url };
1434     if (m_registrableDomain && *m_registrableDomain != registrableDomain) {
1435         // Null out registrable domain since this process has now been used for several domains.
1436         m_registrableDomain = WebCore::RegistrableDomain { };
1437         return;
1438     }
1439
1440     // Associate the process with this registrable domain.
1441     m_registrableDomain = WTFMove(registrableDomain);
1442 }
1443
1444 void WebProcessProxy::incrementSuspendedPageCount()
1445 {
1446     ++m_suspendedPageCount;
1447     if (m_suspendedPageCount == 1)
1448         send(Messages::WebProcess::SetHasSuspendedPageProxy(true), 0);
1449 }
1450
1451 void WebProcessProxy::decrementSuspendedPageCount()
1452 {
1453     ASSERT(m_suspendedPageCount);
1454     --m_suspendedPageCount;
1455     if (!m_suspendedPageCount)
1456         send(Messages::WebProcess::SetHasSuspendedPageProxy(false), 0);
1457 }
1458
1459 #if PLATFORM(WATCHOS)
1460
1461 void WebProcessProxy::takeBackgroundActivityTokenForFullscreenInput()
1462 {
1463     if (m_backgroundActivityTokenForFullscreenFormControls)
1464         return;
1465
1466     m_backgroundActivityTokenForFullscreenFormControls = m_throttler.backgroundActivityToken();
1467     RELEASE_LOG(ProcessSuspension, "UIProcess is taking a background assertion because it is presenting fullscreen UI for form controls.");
1468 }
1469
1470 void WebProcessProxy::releaseBackgroundActivityTokenForFullscreenInput()
1471 {
1472     if (!m_backgroundActivityTokenForFullscreenFormControls)
1473         return;
1474
1475     m_backgroundActivityTokenForFullscreenFormControls = nullptr;
1476     RELEASE_LOG(ProcessSuspension, "UIProcess is releasing a background assertion because it has dismissed fullscreen UI for form controls.");
1477 }
1478
1479 #endif
1480
1481 } // namespace WebKit
1482
1483 #undef MESSAGE_CHECK
1484 #undef MESSAGE_CHECK_URL