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