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