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