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