1/*
2 * Copyright (C) 2010-2018 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 "WebProcessPool.h"
28
29#include "APIArray.h"
30#include "APIAutomationClient.h"
31#include "APICustomProtocolManagerClient.h"
32#include "APIDownloadClient.h"
33#include "APIHTTPCookieStore.h"
34#include "APIInjectedBundleClient.h"
35#include "APILegacyContextHistoryClient.h"
36#include "APINavigation.h"
37#include "APIPageConfiguration.h"
38#include "APIProcessPoolConfiguration.h"
39#include "AuxiliaryProcessMessages.h"
40#include "DownloadProxy.h"
41#include "DownloadProxyMessages.h"
42#include "GamepadData.h"
43#include "HighPerformanceGraphicsUsageSampler.h"
44#include "LogInitialization.h"
45#include "Logging.h"
46#include "NetworkProcessCreationParameters.h"
47#include "NetworkProcessMessages.h"
48#include "NetworkProcessProxy.h"
49#include "PerActivityStateCPUUsageSampler.h"
50#include "PluginProcessManager.h"
51#include "SandboxExtension.h"
52#include "ServiceWorkerProcessProxy.h"
53#include "StatisticsData.h"
54#include "TextChecker.h"
55#include "UIGamepad.h"
56#include "UIGamepadProvider.h"
57#include "WKContextPrivate.h"
58#include "WebAutomationSession.h"
59#include "WebBackForwardList.h"
60#include "WebBackForwardListItem.h"
61#include "WebCertificateInfo.h"
62#include "WebContextSupplement.h"
63#include "WebCookieManagerProxy.h"
64#include "WebCoreArgumentCoders.h"
65#include "WebGeolocationManagerProxy.h"
66#include "WebInspectorUtilities.h"
67#include "WebKit2Initialize.h"
68#include "WebMemorySampler.h"
69#include "WebNotificationManagerProxy.h"
70#include "WebPageGroup.h"
71#include "WebPreferences.h"
72#include "WebPreferencesKeys.h"
73#include "WebProcessCache.h"
74#include "WebProcessCreationParameters.h"
75#include "WebProcessDataStoreParameters.h"
76#include "WebProcessMessages.h"
77#include "WebProcessPoolMessages.h"
78#include "WebProcessProxy.h"
79#include "WebsiteDataStore.h"
80#include "WebsiteDataStoreParameters.h"
81#include <JavaScriptCore/JSCInlines.h>
82#include <WebCore/ApplicationCacheStorage.h>
83#include <WebCore/LogInitialization.h>
84#include <WebCore/MockRealtimeMediaSourceCenter.h>
85#include <WebCore/NetworkStorageSession.h>
86#include <WebCore/PlatformScreen.h>
87#include <WebCore/ProcessIdentifier.h>
88#include <WebCore/ProcessWarming.h>
89#include <WebCore/ResourceRequest.h>
90#include <WebCore/RuntimeApplicationChecks.h>
91#include <WebCore/RuntimeEnabledFeatures.h>
92#include <pal/SessionID.h>
93#include <wtf/Language.h>
94#include <wtf/MainThread.h>
95#include <wtf/NeverDestroyed.h>
96#include <wtf/ProcessPrivilege.h>
97#include <wtf/RunLoop.h>
98#include <wtf/Scope.h>
99#include <wtf/URLParser.h>
100#include <wtf/WallTime.h>
101#include <wtf/text/StringBuilder.h>
102#include <wtf/text/StringConcatenateNumbers.h>
103
104#if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER)
105#include "LegacyCustomProtocolManagerMessages.h"
106#endif
107
108#if ENABLE(SERVICE_CONTROLS)
109#include "ServicesController.h"
110#endif
111
112#if ENABLE(REMOTE_INSPECTOR)
113#include <JavaScriptCore/RemoteInspector.h>
114#endif
115
116#if OS(LINUX)
117#include "MemoryPressureMonitor.h"
118#endif
119
120#if PLATFORM(COCOA)
121#include "VersionChecks.h"
122#endif
123
124#ifndef NDEBUG
125#include <wtf/RefCountedLeakCounter.h>
126#endif
127
128namespace WebKit {
129using namespace WebCore;
130
131DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, processPoolCounter, ("WebProcessPool"));
132
133const Seconds serviceWorkerTerminationDelay { 5_s };
134
135static uint64_t generateListenerIdentifier()
136{
137 static uint64_t nextIdentifier = 1;
138 return nextIdentifier++;
139}
140
141static HashMap<uint64_t, Function<void(WebProcessPool&)>>& processPoolCreationListenerFunctionMap()
142{
143 static NeverDestroyed<HashMap<uint64_t, Function<void(WebProcessPool&)>>> map;
144 return map;
145}
146
147uint64_t WebProcessPool::registerProcessPoolCreationListener(Function<void(WebProcessPool&)>&& function)
148{
149 ASSERT(function);
150
151 auto identifier = generateListenerIdentifier();
152 processPoolCreationListenerFunctionMap().set(identifier, WTFMove(function));
153 return identifier;
154}
155
156void WebProcessPool::unregisterProcessPoolCreationListener(uint64_t identifier)
157{
158 processPoolCreationListenerFunctionMap().remove(identifier);
159}
160
161Ref<WebProcessPool> WebProcessPool::create(API::ProcessPoolConfiguration& configuration)
162{
163 InitializeWebKit2();
164 return adoptRef(*new WebProcessPool(configuration));
165}
166
167void WebProcessPool::notifyThisWebProcessPoolWasCreated()
168{
169 auto& listenerMap = processPoolCreationListenerFunctionMap();
170
171 Vector<uint64_t> identifiers;
172 identifiers.reserveInitialCapacity(listenerMap.size());
173 for (auto identifier : listenerMap.keys())
174 identifiers.uncheckedAppend(identifier);
175
176 for (auto identifier : identifiers) {
177 auto iterator = listenerMap.find(identifier);
178 if (iterator == listenerMap.end())
179 continue;
180
181 // To make sure the Function object stays alive until after the function call has been made,
182 // we temporarily move it out of the map.
183 // This protects it from the Function calling unregisterProcessPoolCreationListener thereby
184 // removing itself from the map of listeners.
185 // If the identifier still exists in the map later, we move it back in.
186 Function<void(WebProcessPool&)> function = WTFMove(iterator->value);
187 function(*this);
188
189 iterator = listenerMap.find(identifier);
190 if (iterator != listenerMap.end()) {
191 ASSERT(!iterator->value);
192 iterator->value = WTFMove(function);
193 }
194 }
195}
196
197static Vector<WebProcessPool*>& processPools()
198{
199 static NeverDestroyed<Vector<WebProcessPool*>> processPools;
200 return processPools;
201}
202
203const Vector<WebProcessPool*>& WebProcessPool::allProcessPools()
204{
205 return processPools();
206}
207
208static Ref<WebsiteDataStoreConfiguration> legacyWebsiteDataStoreConfiguration(API::ProcessPoolConfiguration& processPoolConfiguration)
209{
210 auto configuration = WebsiteDataStoreConfiguration::create();
211
212 configuration->setCacheStorageDirectory(String(API::WebsiteDataStore::defaultCacheStorageDirectory()));
213 configuration->setServiceWorkerRegistrationDirectory(String(API::WebsiteDataStore::defaultServiceWorkerRegistrationDirectory()));
214 configuration->setLocalStorageDirectory(String(processPoolConfiguration.localStorageDirectory()));
215 configuration->setWebSQLDatabaseDirectory(String(processPoolConfiguration.webSQLDatabaseDirectory()));
216 configuration->setApplicationCacheDirectory(String(processPoolConfiguration.applicationCacheDirectory()));
217 configuration->setApplicationCacheFlatFileSubdirectoryName(String(processPoolConfiguration.applicationCacheFlatFileSubdirectoryName()));
218 configuration->setMediaCacheDirectory(String(processPoolConfiguration.mediaCacheDirectory()));
219 configuration->setMediaKeysStorageDirectory(String(processPoolConfiguration.mediaKeysStorageDirectory()));
220 configuration->setIndexedDBDatabaseDirectory(String(processPoolConfiguration.indexedDBDatabaseDirectory()));
221 configuration->setResourceLoadStatisticsDirectory(String(processPoolConfiguration.resourceLoadStatisticsDirectory()));
222 configuration->setNetworkCacheDirectory(String(processPoolConfiguration.diskCacheDirectory()));
223 configuration->setJavaScriptConfigurationDirectory(String(processPoolConfiguration.javaScriptConfigurationDirectory()));
224
225 return configuration;
226}
227
228static HashSet<String, ASCIICaseInsensitiveHash>& globalURLSchemesWithCustomProtocolHandlers()
229{
230 static NeverDestroyed<HashSet<String, ASCIICaseInsensitiveHash>> set;
231 return set;
232}
233
234WebProcessPool::WebProcessPool(API::ProcessPoolConfiguration& configuration)
235 : m_configuration(configuration.copy())
236 , m_defaultPageGroup(WebPageGroup::create())
237 , m_injectedBundleClient(std::make_unique<API::InjectedBundleClient>())
238 , m_automationClient(std::make_unique<API::AutomationClient>())
239 , m_downloadClient(std::make_unique<API::DownloadClient>())
240 , m_historyClient(std::make_unique<API::LegacyContextHistoryClient>())
241 , m_customProtocolManagerClient(std::make_unique<API::CustomProtocolManagerClient>())
242 , m_visitedLinkStore(VisitedLinkStore::create())
243#if PLATFORM(MAC)
244 , m_highPerformanceGraphicsUsageSampler(std::make_unique<HighPerformanceGraphicsUsageSampler>(*this))
245 , m_perActivityStateCPUUsageSampler(std::make_unique<PerActivityStateCPUUsageSampler>(*this))
246#endif
247 , m_alwaysRunsAtBackgroundPriority(m_configuration->alwaysRunsAtBackgroundPriority())
248 , m_shouldTakeUIBackgroundAssertion(m_configuration->shouldTakeUIBackgroundAssertion())
249 , m_userObservablePageCounter([this](RefCounterEvent) { updateProcessSuppressionState(); })
250 , m_processSuppressionDisabledForPageCounter([this](RefCounterEvent) { updateProcessSuppressionState(); })
251 , m_hiddenPageThrottlingAutoIncreasesCounter([this](RefCounterEvent) { m_hiddenPageThrottlingTimer.startOneShot(0_s); })
252 , m_hiddenPageThrottlingTimer(RunLoop::main(), this, &WebProcessPool::updateHiddenPageThrottlingAutoIncreaseLimit)
253 , m_serviceWorkerProcessesTerminationTimer(RunLoop::main(), this, &WebProcessPool::terminateServiceWorkerProcesses)
254#if PLATFORM(IOS_FAMILY)
255 , m_foregroundWebProcessCounter([this](RefCounterEvent) { updateProcessAssertions(); })
256 , m_backgroundWebProcessCounter([this](RefCounterEvent) { updateProcessAssertions(); })
257#endif
258 , m_webProcessCache(makeUniqueRef<WebProcessCache>(*this))
259{
260 static std::once_flag onceFlag;
261 std::call_once(onceFlag, [] {
262 WTF::setProcessPrivileges(allPrivileges());
263 WebCore::NetworkStorageSession::permitProcessToUseCookieAPI(true);
264 Process::setIdentifier(WebCore::ProcessIdentifier::generate());
265 });
266
267 if (m_configuration->shouldHaveLegacyDataStore())
268 m_websiteDataStore = API::WebsiteDataStore::createLegacy(legacyWebsiteDataStoreConfiguration(m_configuration));
269
270 if (!m_websiteDataStore && API::WebsiteDataStore::defaultDataStoreExists())
271 m_websiteDataStore = API::WebsiteDataStore::defaultDataStore();
272
273 for (auto& scheme : m_configuration->alwaysRevalidatedURLSchemes())
274 m_schemesToRegisterAsAlwaysRevalidated.add(scheme);
275
276 for (const auto& urlScheme : m_configuration->cachePartitionedURLSchemes())
277 m_schemesToRegisterAsCachePartitioned.add(urlScheme);
278
279 platformInitialize();
280
281#if OS(LINUX)
282 MemoryPressureMonitor::singleton().start();
283#endif
284
285 addMessageReceiver(Messages::WebProcessPool::messageReceiverName(), *this);
286
287 // NOTE: These sub-objects must be initialized after m_messageReceiverMap..
288 addSupplement<WebCookieManagerProxy>();
289 addSupplement<WebGeolocationManagerProxy>();
290 addSupplement<WebNotificationManagerProxy>();
291#if ENABLE(MEDIA_SESSION)
292 addSupplement<WebMediaSessionFocusManager>();
293#endif
294
295 processPools().append(this);
296
297 addLanguageChangeObserver(this, languageChanged);
298
299 resolvePathsForSandboxExtensions();
300
301#if !LOG_DISABLED || !RELEASE_LOG_DISABLED
302 WebCore::initializeLogChannelsIfNecessary();
303 WebKit::initializeLogChannelsIfNecessary();
304#endif // !LOG_DISABLED || !RELEASE_LOG_DISABLED
305
306#ifndef NDEBUG
307 processPoolCounter.increment();
308#endif
309
310 notifyThisWebProcessPoolWasCreated();
311
312 updateMaxSuspendedPageCount();
313}
314
315WebProcessPool::~WebProcessPool()
316{
317 m_webProcessCache->clear();
318
319 bool removed = processPools().removeFirst(this);
320 ASSERT_UNUSED(removed, removed);
321
322 removeLanguageChangeObserver(this);
323
324 m_messageReceiverMap.invalidate();
325
326 for (auto& supplement : m_supplements.values()) {
327 supplement->processPoolDestroyed();
328 supplement->clearProcessPool();
329 }
330
331 invalidateCallbackMap(m_dictionaryCallbacks, CallbackBase::Error::OwnerWasInvalidated);
332
333 platformInvalidateContext();
334
335#ifndef NDEBUG
336 processPoolCounter.decrement();
337#endif
338
339 if (m_networkProcess)
340 m_networkProcess->shutDownProcess();
341
342#if ENABLE(GAMEPAD)
343 if (!m_processesUsingGamepads.isEmpty())
344 UIGamepadProvider::singleton().processPoolStoppedUsingGamepads(*this);
345#endif
346
347 // Only remaining processes should be pre-warmed ones as other keep the process pool alive.
348 while (!m_processes.isEmpty()) {
349 auto& process = m_processes.first();
350
351 ASSERT(process->isPrewarmed());
352 // We need to be the only one holding a reference to the pre-warmed process so that it gets destroyed.
353 // WebProcessProxies currently always expect to have a WebProcessPool.
354 ASSERT(process->hasOneRef());
355
356 process->shutDown();
357 }
358}
359
360void WebProcessPool::initializeClient(const WKContextClientBase* client)
361{
362 m_client.initialize(client);
363}
364
365void WebProcessPool::setInjectedBundleClient(std::unique_ptr<API::InjectedBundleClient>&& client)
366{
367 if (!client)
368 m_injectedBundleClient = std::make_unique<API::InjectedBundleClient>();
369 else
370 m_injectedBundleClient = WTFMove(client);
371}
372
373void WebProcessPool::initializeConnectionClient(const WKContextConnectionClientBase* client)
374{
375 m_connectionClient.initialize(client);
376}
377
378void WebProcessPool::setHistoryClient(std::unique_ptr<API::LegacyContextHistoryClient>&& historyClient)
379{
380 if (!historyClient)
381 m_historyClient = std::make_unique<API::LegacyContextHistoryClient>();
382 else
383 m_historyClient = WTFMove(historyClient);
384}
385
386void WebProcessPool::setDownloadClient(std::unique_ptr<API::DownloadClient>&& downloadClient)
387{
388 if (!downloadClient)
389 m_downloadClient = std::make_unique<API::DownloadClient>();
390 else
391 m_downloadClient = WTFMove(downloadClient);
392}
393
394void WebProcessPool::setAutomationClient(std::unique_ptr<API::AutomationClient>&& automationClient)
395{
396 if (!automationClient)
397 m_automationClient = std::make_unique<API::AutomationClient>();
398 else
399 m_automationClient = WTFMove(automationClient);
400}
401
402void WebProcessPool::setLegacyCustomProtocolManagerClient(std::unique_ptr<API::CustomProtocolManagerClient>&& customProtocolManagerClient)
403{
404#if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER)
405 if (!customProtocolManagerClient)
406 m_customProtocolManagerClient = std::make_unique<API::CustomProtocolManagerClient>();
407 else
408 m_customProtocolManagerClient = WTFMove(customProtocolManagerClient);
409#endif
410}
411
412void WebProcessPool::setCustomWebContentServiceBundleIdentifier(const String& customWebContentServiceBundleIdentifier)
413{
414 // Guard against API misuse.
415 if (!customWebContentServiceBundleIdentifier.isAllASCII())
416 CRASH();
417
418 m_configuration->setCustomWebContentServiceBundleIdentifier(customWebContentServiceBundleIdentifier);
419}
420
421IPC::Connection* WebProcessPool::networkingProcessConnection()
422{
423 return m_networkProcess->connection();
424}
425
426void WebProcessPool::languageChanged(void* context)
427{
428 static_cast<WebProcessPool*>(context)->languageChanged();
429}
430
431void WebProcessPool::languageChanged()
432{
433 sendToAllProcesses(Messages::WebProcess::UserPreferredLanguagesChanged(userPreferredLanguages()));
434#if USE(SOUP)
435 if (m_networkProcess)
436 m_networkProcess->send(Messages::NetworkProcess::UserPreferredLanguagesChanged(userPreferredLanguages()), 0);
437#endif
438}
439
440void WebProcessPool::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled)
441{
442 sendToAllProcesses(Messages::WebProcess::FullKeyboardAccessModeChanged(fullKeyboardAccessEnabled));
443}
444
445#if OS(LINUX)
446void WebProcessPool::sendMemoryPressureEvent(bool isCritical)
447{
448 sendToAllProcesses(Messages::AuxiliaryProcess::DidReceiveMemoryPressureEvent(isCritical));
449 sendToNetworkingProcess(Messages::AuxiliaryProcess::DidReceiveMemoryPressureEvent(isCritical));
450#if ENABLE(NETSCAPE_PLUGIN_API)
451 PluginProcessManager::singleton().sendMemoryPressureEvent(isCritical);
452#endif
453}
454#endif
455
456void WebProcessPool::textCheckerStateChanged()
457{
458 sendToAllProcesses(Messages::WebProcess::SetTextCheckerState(TextChecker::state()));
459}
460
461void WebProcessPool::setApplicationIsActive(bool isActive)
462{
463 m_webProcessCache->setApplicationIsActive(isActive);
464}
465
466void WebProcessPool::screenPropertiesStateChanged()
467{
468#if PLATFORM(MAC)
469 auto screenProperties = WebCore::collectScreenProperties();
470 sendToAllProcesses(Messages::WebProcess::SetScreenProperties(screenProperties));
471#endif
472}
473
474NetworkProcessProxy& WebProcessPool::ensureNetworkProcess(WebsiteDataStore* withWebsiteDataStore)
475{
476 if (m_networkProcess) {
477 if (withWebsiteDataStore) {
478 m_networkProcess->addSession(makeRef(*withWebsiteDataStore));
479 withWebsiteDataStore->clearPendingCookies();
480 }
481 return *m_networkProcess;
482 }
483
484 m_networkProcess = std::make_unique<NetworkProcessProxy>(*this);
485
486 NetworkProcessCreationParameters parameters;
487
488 if (m_websiteDataStore) {
489 parameters.defaultDataStoreParameters.pendingCookies = copyToVector(m_websiteDataStore->websiteDataStore().pendingCookies());
490 m_websiteDataStore->websiteDataStore().clearPendingCookies();
491#if PLATFORM(COCOA)
492 parameters.defaultDataStoreParameters.networkSessionParameters.sourceApplicationBundleIdentifier = m_websiteDataStore->websiteDataStore().sourceApplicationBundleIdentifier();
493 parameters.defaultDataStoreParameters.networkSessionParameters.sourceApplicationSecondaryIdentifier = m_websiteDataStore->websiteDataStore().sourceApplicationSecondaryIdentifier();
494 parameters.defaultDataStoreParameters.networkSessionParameters.allowsTLSFallback = m_websiteDataStore->websiteDataStore().allowsTLSFallback() ? AllowsTLSFallback::Yes : AllowsTLSFallback::No;
495#endif
496 m_websiteDataStore->websiteDataStore().networkingHasBegun();
497 }
498
499 parameters.cacheModel = cacheModel();
500 parameters.canHandleHTTPSServerTrustEvaluation = m_canHandleHTTPSServerTrustEvaluation;
501
502 for (auto& scheme : globalURLSchemesWithCustomProtocolHandlers())
503 parameters.urlSchemesRegisteredForCustomProtocols.append(scheme);
504
505 for (auto& scheme : m_urlSchemesRegisteredForCustomProtocols)
506 parameters.urlSchemesRegisteredForCustomProtocols.append(scheme);
507
508 parameters.diskCacheDirectory = m_configuration->diskCacheDirectory();
509 if (!parameters.diskCacheDirectory.isEmpty())
510 SandboxExtension::createHandleForReadWriteDirectory(parameters.diskCacheDirectory, parameters.diskCacheDirectoryExtensionHandle);
511#if ENABLE(NETWORK_CACHE_SPECULATIVE_REVALIDATION)
512 parameters.shouldEnableNetworkCacheSpeculativeRevalidation = m_configuration->diskCacheSpeculativeValidationEnabled();
513#endif
514
515#if PLATFORM(IOS_FAMILY)
516 String cookieStorageDirectory = this->cookieStorageDirectory();
517 if (!cookieStorageDirectory.isEmpty())
518 SandboxExtension::createHandleForReadWriteDirectory(cookieStorageDirectory, parameters.cookieStorageDirectoryExtensionHandle);
519
520 String containerCachesDirectory = this->networkingCachesDirectory();
521 if (!containerCachesDirectory.isEmpty())
522 SandboxExtension::createHandleForReadWriteDirectory(containerCachesDirectory, parameters.containerCachesDirectoryExtensionHandle);
523
524 String parentBundleDirectory = this->parentBundleDirectory();
525 if (!parentBundleDirectory.isEmpty())
526 SandboxExtension::createHandle(parentBundleDirectory, SandboxExtension::Type::ReadOnly, parameters.parentBundleDirectoryExtensionHandle);
527
528#if ENABLE(INDEXED_DATABASE)
529 SandboxExtension::createHandleForTemporaryFile(emptyString(), SandboxExtension::Type::ReadWrite, parameters.defaultDataStoreParameters.indexedDatabaseTempBlobDirectoryExtensionHandle);
530#endif
531#endif
532
533 parameters.hstsStorageDirectory = m_configuration->hstsStorageDirectory();
534 if (!parameters.hstsStorageDirectory.isNull())
535 SandboxExtension::createHandleForReadWriteDirectory(parameters.hstsStorageDirectory, parameters.hstsStorageDirectoryExtensionHandle);
536
537 parameters.shouldUseTestingNetworkSession = m_shouldUseTestingNetworkSession;
538
539 parameters.urlSchemesRegisteredAsSecure = copyToVector(m_schemesToRegisterAsSecure);
540 parameters.urlSchemesRegisteredAsBypassingContentSecurityPolicy = copyToVector(m_schemesToRegisterAsBypassingContentSecurityPolicy);
541 parameters.urlSchemesRegisteredAsLocal = copyToVector(m_schemesToRegisterAsLocal);
542 parameters.urlSchemesRegisteredAsNoAccess = copyToVector(m_schemesToRegisterAsNoAccess);
543 parameters.urlSchemesRegisteredAsDisplayIsolated = copyToVector(m_schemesToRegisterAsDisplayIsolated);
544 parameters.urlSchemesRegisteredAsCORSEnabled = copyToVector(m_schemesToRegisterAsCORSEnabled);
545 parameters.urlSchemesRegisteredAsCanDisplayOnlyIfCanRequest = copyToVector(m_schemesToRegisterAsCanDisplayOnlyIfCanRequest);
546
547#if ENABLE(INDEXED_DATABASE)
548 // *********
549 // IMPORTANT: Do not change the directory structure for indexed databases on disk without first consulting a reviewer from Apple (<rdar://problem/17454712>)
550 // *********
551 parameters.defaultDataStoreParameters.indexedDatabaseDirectory = m_configuration->indexedDBDatabaseDirectory();
552 if (parameters.defaultDataStoreParameters.indexedDatabaseDirectory.isEmpty())
553 parameters.defaultDataStoreParameters.indexedDatabaseDirectory = API::WebsiteDataStore::defaultDataStore()->websiteDataStore().parameters().indexedDatabaseDirectory;
554
555 SandboxExtension::createHandleForReadWriteDirectory(parameters.defaultDataStoreParameters.indexedDatabaseDirectory, parameters.defaultDataStoreParameters.indexedDatabaseDirectoryExtensionHandle);
556 m_networkProcess->createSymLinkForFileUpgrade(parameters.defaultDataStoreParameters.indexedDatabaseDirectory);
557#endif
558
559#if ENABLE(SERVICE_WORKER)
560 if (m_websiteDataStore)
561 parameters.serviceWorkerRegistrationDirectory = m_websiteDataStore->websiteDataStore().resolvedServiceWorkerRegistrationDirectory();
562 if (!parameters.serviceWorkerRegistrationDirectory)
563 parameters.serviceWorkerRegistrationDirectory = API::WebsiteDataStore::defaultServiceWorkerRegistrationDirectory();
564 SandboxExtension::createHandleForReadWriteDirectory(parameters.serviceWorkerRegistrationDirectory, parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
565
566 if (!m_schemesServiceWorkersCanHandle.isEmpty())
567 parameters.urlSchemesServiceWorkersCanHandle = copyToVector(m_schemesServiceWorkersCanHandle);
568
569 parameters.shouldDisableServiceWorkerProcessTerminationDelay = m_shouldDisableServiceWorkerProcessTerminationDelay;
570#endif
571
572 auto localStorageDirectory = m_websiteDataStore ? m_websiteDataStore->websiteDataStore().resolvedLocalStorageDirectory() : nullString();
573 if (!localStorageDirectory)
574 localStorageDirectory = API::WebsiteDataStore::defaultLocalStorageDirectory();
575 parameters.defaultDataStoreParameters.networkSessionParameters.localStorageDirectory = localStorageDirectory;
576 SandboxExtension::createHandleForReadWriteDirectory(localStorageDirectory, parameters.defaultDataStoreParameters.networkSessionParameters.localStorageDirectoryExtensionHandle);
577
578 if (m_websiteDataStore)
579 parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectory = m_websiteDataStore->websiteDataStore().resolvedResourceLoadStatisticsDirectory();
580 if (parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectory.isEmpty())
581 parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectory = API::WebsiteDataStore::defaultResourceLoadStatisticsDirectory();
582
583 SandboxExtension::createHandleForReadWriteDirectory(parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectory, parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectoryExtensionHandle);
584
585 bool enableResourceLoadStatistics = false;
586 bool shouldIncludeLocalhost = true;
587 bool enableResourceLoadStatisticsDebugMode = false;
588 WebCore::RegistrableDomain manualPrevalentResource { };
589 if (withWebsiteDataStore) {
590 enableResourceLoadStatistics = withWebsiteDataStore->resourceLoadStatisticsEnabled();
591 if (enableResourceLoadStatistics) {
592 auto networkSessionParameters = withWebsiteDataStore->parameters().networkSessionParameters;
593 shouldIncludeLocalhost = networkSessionParameters.shouldIncludeLocalhostInResourceLoadStatistics;
594 enableResourceLoadStatisticsDebugMode = networkSessionParameters.enableResourceLoadStatisticsDebugMode;
595 manualPrevalentResource = networkSessionParameters.resourceLoadStatisticsManualPrevalentResource;
596 }
597
598 parameters.defaultDataStoreParameters.perOriginStorageQuota = withWebsiteDataStore->perOriginStorageQuota();
599 parameters.defaultDataStoreParameters.perThirdPartyOriginStorageQuota = withWebsiteDataStore->perThirdPartyOriginStorageQuota();
600 } else if (m_websiteDataStore) {
601 enableResourceLoadStatistics = m_websiteDataStore->resourceLoadStatisticsEnabled();
602 if (enableResourceLoadStatistics) {
603 auto networkSessionParameters = m_websiteDataStore->websiteDataStore().parameters().networkSessionParameters;
604 shouldIncludeLocalhost = networkSessionParameters.shouldIncludeLocalhostInResourceLoadStatistics;
605 enableResourceLoadStatisticsDebugMode = networkSessionParameters.enableResourceLoadStatisticsDebugMode;
606 manualPrevalentResource = networkSessionParameters.resourceLoadStatisticsManualPrevalentResource;
607 }
608
609 parameters.defaultDataStoreParameters.perOriginStorageQuota = m_websiteDataStore->websiteDataStore().perOriginStorageQuota();
610 parameters.defaultDataStoreParameters.perThirdPartyOriginStorageQuota = m_websiteDataStore->websiteDataStore().perThirdPartyOriginStorageQuota();
611 }
612
613 parameters.defaultDataStoreParameters.networkSessionParameters.enableResourceLoadStatistics = enableResourceLoadStatistics;
614 parameters.defaultDataStoreParameters.networkSessionParameters.shouldIncludeLocalhostInResourceLoadStatistics = shouldIncludeLocalhost;
615 parameters.defaultDataStoreParameters.networkSessionParameters.enableResourceLoadStatisticsDebugMode = enableResourceLoadStatisticsDebugMode;
616 parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsManualPrevalentResource = manualPrevalentResource;
617
618 // Add any platform specific parameters
619 platformInitializeNetworkProcess(parameters);
620
621 // Initialize the network process.
622 m_networkProcess->send(Messages::NetworkProcess::InitializeNetworkProcess(parameters), 0);
623
624 if (WebPreferences::anyPagesAreUsingPrivateBrowsing())
625 m_networkProcess->send(Messages::NetworkProcess::AddWebsiteDataStore(WebsiteDataStoreParameters::legacyPrivateSessionParameters()), 0);
626
627#if PLATFORM(COCOA)
628 m_networkProcess->send(Messages::NetworkProcess::SetQOS(networkProcessLatencyQOS(), networkProcessThroughputQOS()), 0);
629#endif
630
631 if (m_didNetworkProcessCrash) {
632 m_didNetworkProcessCrash = false;
633 reinstateNetworkProcessAssertionState(*m_networkProcess);
634 }
635
636 if (withWebsiteDataStore) {
637 m_networkProcess->addSession(makeRef(*withWebsiteDataStore));
638 withWebsiteDataStore->clearPendingCookies();
639 }
640
641 // Make sure the network process knows about all the sessions that have been registered before it started.
642 for (auto& sessionID : m_sessionToPageIDsMap.keys()) {
643 if (auto* websiteDataStore = WebsiteDataStore::existingNonDefaultDataStoreForSessionID(sessionID))
644 m_networkProcess->addSession(*websiteDataStore);
645 }
646
647 return *m_networkProcess;
648}
649
650void WebProcessPool::networkProcessCrashed(NetworkProcessProxy& networkProcessProxy, Vector<std::pair<RefPtr<WebProcessProxy>, Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply>>&& pendingReplies)
651{
652 ASSERT(m_networkProcess);
653 ASSERT(&networkProcessProxy == m_networkProcess.get());
654 m_didNetworkProcessCrash = true;
655
656 for (auto& supplement : m_supplements.values())
657 supplement->processDidClose(&networkProcessProxy);
658
659 m_client.networkProcessDidCrash(this);
660
661 if (m_automationSession)
662 m_automationSession->terminate();
663
664 // Leave the process proxy around during client call, so that the client could query the process identifier.
665 m_networkProcess = nullptr;
666
667 // Attempt to re-launch.
668 if (pendingReplies.isEmpty())
669 return;
670 auto& newNetworkProcess = ensureNetworkProcess();
671 for (auto& reply : pendingReplies)
672 newNetworkProcess.getNetworkProcessConnection(*reply.first, WTFMove(reply.second));
673}
674
675void WebProcessPool::getNetworkProcessConnection(WebProcessProxy& webProcessProxy, Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply&& reply)
676{
677 ensureNetworkProcess();
678 ASSERT(m_networkProcess);
679
680 m_networkProcess->getNetworkProcessConnection(webProcessProxy, WTFMove(reply));
681}
682
683#if ENABLE(SERVICE_WORKER)
684void WebProcessPool::establishWorkerContextConnectionToNetworkProcess(NetworkProcessProxy& proxy, RegistrableDomain&& registrableDomain, Optional<PAL::SessionID> sessionID)
685{
686 ASSERT_UNUSED(proxy, &proxy == m_networkProcess.get());
687
688 if (m_serviceWorkerProcesses.contains(registrableDomain))
689 return;
690
691 m_mayHaveRegisteredServiceWorkers.clear();
692
693 WebsiteDataStore* websiteDataStore = nullptr;
694 if (sessionID)
695 websiteDataStore = WebsiteDataStore::existingNonDefaultDataStoreForSessionID(*sessionID);
696
697 if (!websiteDataStore) {
698 if (!m_websiteDataStore)
699 m_websiteDataStore = API::WebsiteDataStore::defaultDataStore().ptr();
700 websiteDataStore = &m_websiteDataStore->websiteDataStore();
701 }
702
703 if (m_serviceWorkerProcesses.isEmpty())
704 sendToAllProcesses(Messages::WebProcess::RegisterServiceWorkerClients { });
705
706 auto serviceWorkerProcessProxy = ServiceWorkerProcessProxy::create(*this, registrableDomain, *websiteDataStore);
707 m_serviceWorkerProcesses.add(WTFMove(registrableDomain), serviceWorkerProcessProxy.ptr());
708
709 updateProcessAssertions();
710 initializeNewWebProcess(serviceWorkerProcessProxy, websiteDataStore);
711
712 auto* serviceWorkerProcessProxyPtr = serviceWorkerProcessProxy.ptr();
713 m_processes.append(WTFMove(serviceWorkerProcessProxy));
714
715 serviceWorkerProcessProxyPtr->start(m_serviceWorkerPreferences ? m_serviceWorkerPreferences.value() : m_defaultPageGroup->preferences().store(), sessionID);
716 if (!m_serviceWorkerUserAgent.isNull())
717 serviceWorkerProcessProxyPtr->setUserAgent(m_serviceWorkerUserAgent);
718}
719#endif
720
721void WebProcessPool::disableServiceWorkerProcessTerminationDelay()
722{
723#if ENABLE(SERVICE_WORKER)
724 if (m_shouldDisableServiceWorkerProcessTerminationDelay)
725 return;
726
727 m_shouldDisableServiceWorkerProcessTerminationDelay = true;
728 if (m_networkProcess)
729 m_networkProcess->send(Messages::NetworkProcess::DisableServiceWorkerProcessTerminationDelay(), 0);
730#endif
731}
732
733void WebProcessPool::willStartUsingPrivateBrowsing()
734{
735 for (auto* processPool : allProcessPools())
736 processPool->setAnyPageGroupMightHavePrivateBrowsingEnabled(true);
737}
738
739void WebProcessPool::willStopUsingPrivateBrowsing()
740{
741 for (auto* processPool : allProcessPools())
742 processPool->setAnyPageGroupMightHavePrivateBrowsingEnabled(false);
743}
744
745void WebProcessPool::windowServerConnectionStateChanged()
746{
747 size_t processCount = m_processes.size();
748 for (size_t i = 0; i < processCount; ++i)
749 m_processes[i]->windowServerConnectionStateChanged();
750}
751
752void WebProcessPool::setAnyPageGroupMightHavePrivateBrowsingEnabled(bool privateBrowsingEnabled)
753{
754 if (privateBrowsingEnabled) {
755 ensureNetworkProcess().send(Messages::NetworkProcess::AddWebsiteDataStore(WebsiteDataStoreParameters::legacyPrivateSessionParameters()), 0);
756 } else {
757 if (auto* networkProcess = this->networkProcess())
758 networkProcess->removeSession(PAL::SessionID::legacyPrivateSessionID());
759 }
760}
761
762void (*s_invalidMessageCallback)(WKStringRef messageName);
763
764void WebProcessPool::setInvalidMessageCallback(void (*invalidMessageCallback)(WKStringRef messageName))
765{
766 s_invalidMessageCallback = invalidMessageCallback;
767}
768
769void WebProcessPool::didReceiveInvalidMessage(const IPC::StringReference& messageReceiverName, const IPC::StringReference& messageName)
770{
771 if (!s_invalidMessageCallback)
772 return;
773
774 StringBuilder messageNameStringBuilder;
775 messageNameStringBuilder.append(messageReceiverName.data(), messageReceiverName.size());
776 messageNameStringBuilder.append('.');
777 messageNameStringBuilder.append(messageName.data(), messageName.size());
778
779 s_invalidMessageCallback(toAPI(API::String::create(messageNameStringBuilder.toString()).ptr()));
780}
781
782void WebProcessPool::processDidCachePage(WebProcessProxy* process)
783{
784 if (m_processWithPageCache && m_processWithPageCache != process)
785 m_processWithPageCache->releasePageCache();
786 m_processWithPageCache = process;
787}
788
789void WebProcessPool::resolvePathsForSandboxExtensions()
790{
791 m_resolvedPaths.injectedBundlePath = resolvePathForSandboxExtension(injectedBundlePath());
792 m_resolvedPaths.applicationCacheDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->applicationCacheDirectory());
793 m_resolvedPaths.webSQLDatabaseDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->webSQLDatabaseDirectory());
794 m_resolvedPaths.mediaCacheDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->mediaCacheDirectory());
795 m_resolvedPaths.mediaKeyStorageDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->mediaKeysStorageDirectory());
796 m_resolvedPaths.indexedDatabaseDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->indexedDBDatabaseDirectory());
797
798 m_resolvedPaths.additionalWebProcessSandboxExtensionPaths.reserveCapacity(m_configuration->additionalReadAccessAllowedPaths().size());
799 for (const auto& path : m_configuration->additionalReadAccessAllowedPaths())
800 m_resolvedPaths.additionalWebProcessSandboxExtensionPaths.uncheckedAppend(resolvePathForSandboxExtension(path.data()));
801
802 platformResolvePathsForSandboxExtensions();
803}
804
805WebProcessProxy& WebProcessPool::createNewWebProcess(WebsiteDataStore* websiteDataStore, WebProcessProxy::IsPrewarmed isPrewarmed)
806{
807 auto processProxy = WebProcessProxy::create(*this, websiteDataStore, isPrewarmed);
808 auto& process = processProxy.get();
809 initializeNewWebProcess(process, websiteDataStore, isPrewarmed);
810 m_processes.append(WTFMove(processProxy));
811
812 if (m_serviceWorkerProcessesTerminationTimer.isActive())
813 m_serviceWorkerProcessesTerminationTimer.stop();
814
815 return process;
816}
817
818RefPtr<WebProcessProxy> WebProcessPool::tryTakePrewarmedProcess(WebsiteDataStore& websiteDataStore)
819{
820 if (!m_prewarmedProcess)
821 return nullptr;
822
823#if PLATFORM(GTK) || PLATFORM(WPE)
824 // In platforms using Bubblewrap for sandboxing, prewarmed process is launched using the WebProcessPool primary WebsiteDataStore,
825 // so we don't use it in case of using a different WebsiteDataStore.
826 if (m_sandboxEnabled && m_websiteDataStore && &m_websiteDataStore->websiteDataStore() != &websiteDataStore)
827 return nullptr;
828#endif
829
830 ASSERT(m_prewarmedProcess->isPrewarmed());
831 m_prewarmedProcess->markIsNoLongerInPrewarmedPool();
832
833 m_prewarmedProcess->setWebsiteDataStore(websiteDataStore);
834 sendWebProcessDataStoreParameters(*m_prewarmedProcess, websiteDataStore);
835
836 return std::exchange(m_prewarmedProcess, nullptr);
837}
838
839#if PLATFORM(MAC)
840static void displayReconfigurationCallBack(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *userInfo)
841{
842 auto screenProperties = WebCore::collectScreenProperties();
843 for (auto& processPool : WebProcessPool::allProcessPools()) {
844 processPool->sendToAllProcesses(Messages::WebProcess::SetScreenProperties(screenProperties));
845#if ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
846 processPool->sendToAllProcesses(Messages::WebProcess::DisplayConfigurationChanged(display, flags));
847#endif
848 }
849}
850
851static void registerDisplayConfigurationCallback()
852{
853 static std::once_flag onceFlag;
854 std::call_once(
855 onceFlag,
856 [] {
857 CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallBack, nullptr);
858 });
859}
860#endif
861
862void WebProcessPool::sendWebProcessDataStoreParameters(WebProcessProxy& process, WebsiteDataStore& websiteDataStore)
863{
864 WebProcessDataStoreParameters parameters;
865
866 websiteDataStore.resolveDirectoriesIfNecessary();
867
868 parameters.applicationCacheDirectory = websiteDataStore.resolvedApplicationCacheDirectory();
869 if (parameters.applicationCacheDirectory.isEmpty())
870 parameters.applicationCacheDirectory = m_resolvedPaths.applicationCacheDirectory;
871 if (!parameters.applicationCacheDirectory.isEmpty())
872 SandboxExtension::createHandleWithoutResolvingPath(parameters.applicationCacheDirectory, SandboxExtension::Type::ReadWrite, parameters.applicationCacheDirectoryExtensionHandle);
873 parameters.applicationCacheFlatFileSubdirectoryName = m_configuration->applicationCacheFlatFileSubdirectoryName();
874
875 parameters.webSQLDatabaseDirectory = websiteDataStore.resolvedDatabaseDirectory();
876 if (parameters.webSQLDatabaseDirectory.isEmpty())
877 parameters.webSQLDatabaseDirectory = m_resolvedPaths.webSQLDatabaseDirectory;
878 if (!parameters.webSQLDatabaseDirectory.isEmpty())
879 SandboxExtension::createHandleWithoutResolvingPath(parameters.webSQLDatabaseDirectory, SandboxExtension::Type::ReadWrite, parameters.webSQLDatabaseDirectoryExtensionHandle);
880
881 parameters.mediaCacheDirectory = websiteDataStore.resolvedMediaCacheDirectory();
882 if (parameters.mediaCacheDirectory.isEmpty())
883 parameters.mediaCacheDirectory = m_resolvedPaths.mediaCacheDirectory;
884 if (!parameters.mediaCacheDirectory.isEmpty())
885 SandboxExtension::createHandleWithoutResolvingPath(parameters.mediaCacheDirectory, SandboxExtension::Type::ReadWrite, parameters.mediaCacheDirectoryExtensionHandle);
886
887 parameters.mediaKeyStorageDirectory = websiteDataStore.resolvedMediaKeysDirectory();
888 if (parameters.mediaKeyStorageDirectory.isEmpty())
889 parameters.mediaKeyStorageDirectory = m_resolvedPaths.mediaKeyStorageDirectory;
890 if (!parameters.mediaKeyStorageDirectory.isEmpty())
891 SandboxExtension::createHandleWithoutResolvingPath(parameters.mediaKeyStorageDirectory, SandboxExtension::Type::ReadWrite, parameters.mediaKeyStorageDirectoryExtensionHandle);
892
893 if (javaScriptConfigurationFileEnabled()) {
894 parameters.javaScriptConfigurationDirectory = websiteDataStore.resolvedJavaScriptConfigurationDirectory();
895 if (!parameters.javaScriptConfigurationDirectory.isEmpty())
896 SandboxExtension::createHandleWithoutResolvingPath(parameters.javaScriptConfigurationDirectory, SandboxExtension::Type::ReadWrite, parameters.javaScriptConfigurationDirectoryExtensionHandle);
897 }
898
899 parameters.resourceLoadStatisticsEnabled = websiteDataStore.resourceLoadStatisticsEnabled();
900
901 process.send(Messages::WebProcess::SetWebsiteDataStoreParameters(parameters), 0);
902}
903
904void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDataStore* websiteDataStore, WebProcessProxy::IsPrewarmed isPrewarmed)
905{
906 auto initializationActivityToken = process.throttler().backgroundActivityToken();
907 auto scopeExit = makeScopeExit([&process, initializationActivityToken] {
908 // Round-trip to the Web Content process before releasing the
909 // initialization activity token, so that we're sure that all
910 // messages sent from this function have been handled.
911 process.isResponsive([initializationActivityToken] (bool) { });
912 });
913
914 ensureNetworkProcess();
915
916 WebProcessCreationParameters parameters;
917
918 parameters.injectedBundlePath = m_resolvedPaths.injectedBundlePath;
919 if (!parameters.injectedBundlePath.isEmpty())
920 SandboxExtension::createHandleWithoutResolvingPath(parameters.injectedBundlePath, SandboxExtension::Type::ReadOnly, parameters.injectedBundlePathExtensionHandle);
921
922 parameters.additionalSandboxExtensionHandles.allocate(m_resolvedPaths.additionalWebProcessSandboxExtensionPaths.size());
923 for (size_t i = 0, size = m_resolvedPaths.additionalWebProcessSandboxExtensionPaths.size(); i < size; ++i)
924 SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.additionalWebProcessSandboxExtensionPaths[i], SandboxExtension::Type::ReadOnly, parameters.additionalSandboxExtensionHandles[i]);
925
926#if PLATFORM(IOS_FAMILY)
927 setJavaScriptConfigurationFileEnabledFromDefaults();
928#endif
929
930 parameters.cacheModel = cacheModel();
931 parameters.languages = configuration().overrideLanguages().isEmpty() ? userPreferredLanguages() : configuration().overrideLanguages();
932
933 parameters.urlSchemesRegisteredAsEmptyDocument = copyToVector(m_schemesToRegisterAsEmptyDocument);
934 parameters.urlSchemesRegisteredAsSecure = copyToVector(m_schemesToRegisterAsSecure);
935 parameters.urlSchemesRegisteredAsBypassingContentSecurityPolicy = copyToVector(m_schemesToRegisterAsBypassingContentSecurityPolicy);
936 parameters.urlSchemesForWhichDomainRelaxationIsForbidden = copyToVector(m_schemesToSetDomainRelaxationForbiddenFor);
937 parameters.urlSchemesRegisteredAsLocal = copyToVector(m_schemesToRegisterAsLocal);
938 parameters.urlSchemesRegisteredAsNoAccess = copyToVector(m_schemesToRegisterAsNoAccess);
939 parameters.urlSchemesRegisteredAsDisplayIsolated = copyToVector(m_schemesToRegisterAsDisplayIsolated);
940 parameters.urlSchemesRegisteredAsCORSEnabled = copyToVector(m_schemesToRegisterAsCORSEnabled);
941 parameters.urlSchemesRegisteredAsAlwaysRevalidated = copyToVector(m_schemesToRegisterAsAlwaysRevalidated);
942 parameters.urlSchemesRegisteredAsCachePartitioned = copyToVector(m_schemesToRegisterAsCachePartitioned);
943 parameters.urlSchemesServiceWorkersCanHandle = copyToVector(m_schemesServiceWorkersCanHandle);
944 parameters.urlSchemesRegisteredAsCanDisplayOnlyIfCanRequest = copyToVector(m_schemesToRegisterAsCanDisplayOnlyIfCanRequest);
945
946 parameters.shouldAlwaysUseComplexTextCodePath = m_alwaysUsesComplexTextCodePath;
947 parameters.shouldUseFontSmoothing = m_shouldUseFontSmoothing;
948
949 parameters.terminationTimeout = 0_s;
950
951 parameters.textCheckerState = TextChecker::state();
952
953 parameters.fullKeyboardAccessEnabled = WebProcessProxy::fullKeyboardAccessEnabled();
954
955 parameters.defaultRequestTimeoutInterval = API::URLRequest::defaultTimeoutInterval();
956
957#if ENABLE(NOTIFICATIONS)
958 // FIXME: There should be a generic way for supplements to add to the intialization parameters.
959 parameters.notificationPermissions = supplement<WebNotificationManagerProxy>()->notificationPermissions();
960#endif
961
962 parameters.plugInAutoStartOriginHashes = m_plugInAutoStartProvider.autoStartOriginHashesCopy();
963 parameters.plugInAutoStartOrigins = copyToVector(m_plugInAutoStartProvider.autoStartOrigins());
964
965 parameters.memoryCacheDisabled = m_memoryCacheDisabled;
966 parameters.attrStyleEnabled = m_configuration->attrStyleEnabled();
967
968#if ENABLE(SERVICE_CONTROLS)
969 auto& serviceController = ServicesController::singleton();
970 parameters.hasImageServices = serviceController.hasImageServices();
971 parameters.hasSelectionServices = serviceController.hasSelectionServices();
972 parameters.hasRichContentServices = serviceController.hasRichContentServices();
973 serviceController.refreshExistingServices();
974#endif
975
976#if ENABLE(NETSCAPE_PLUGIN_API)
977 parameters.pluginLoadClientPolicies = m_pluginLoadClientPolicies;
978#endif
979
980#if OS(LINUX)
981 parameters.shouldEnableMemoryPressureReliefLogging = true;
982#endif
983
984#if ENABLE(MEDIA_STREAM)
985 parameters.shouldCaptureAudioInUIProcess = m_configuration->shouldCaptureAudioInUIProcess();
986 parameters.shouldCaptureVideoInUIProcess = m_configuration->shouldCaptureVideoInUIProcess();
987 parameters.shouldCaptureDisplayInUIProcess = m_configuration->shouldCaptureDisplayInUIProcess();
988#endif
989
990 parameters.presentingApplicationPID = m_configuration->presentingApplicationPID();
991
992#if PLATFORM(COCOA)
993 parameters.mediaMIMETypes = process.mediaMIMETypes();
994#endif
995
996#if PLATFORM(WPE)
997 parameters.isServiceWorkerProcess = process.isServiceWorkerProcess();
998#endif
999
1000 // Add any platform specific parameters
1001 platformInitializeWebProcess(parameters);
1002
1003 RefPtr<API::Object> injectedBundleInitializationUserData = m_injectedBundleClient->getInjectedBundleInitializationUserData(*this);
1004 if (!injectedBundleInitializationUserData)
1005 injectedBundleInitializationUserData = m_injectedBundleInitializationUserData;
1006 parameters.initializationUserData = UserData(process.transformObjectsToHandles(injectedBundleInitializationUserData.get()));
1007
1008 process.send(Messages::WebProcess::InitializeWebProcess(parameters), 0);
1009
1010#if PLATFORM(COCOA)
1011 process.send(Messages::WebProcess::SetQOS(webProcessLatencyQOS(), webProcessThroughputQOS()), 0);
1012#endif
1013
1014 if (websiteDataStore)
1015 sendWebProcessDataStoreParameters(process, *websiteDataStore);
1016
1017 if (m_automationSession)
1018 process.send(Messages::WebProcess::EnsureAutomationSessionProxy(m_automationSession->sessionIdentifier()), 0);
1019
1020 ASSERT(m_messagesToInjectedBundlePostedToEmptyContext.isEmpty());
1021
1022 if (isPrewarmed == WebProcessProxy::IsPrewarmed::Yes) {
1023 ASSERT(!m_prewarmedProcess);
1024 m_prewarmedProcess = &process;
1025 process.send(Messages::WebProcess::PrewarmGlobally(), 0);
1026 }
1027
1028#if PLATFORM(IOS)
1029 process.send(Messages::WebProcess::BacklightLevelDidChange(displayBrightness()), 0);
1030#endif
1031
1032#if ENABLE(REMOTE_INSPECTOR)
1033 // Initialize remote inspector connection now that we have a sub-process that is hosting one of our web views.
1034 Inspector::RemoteInspector::singleton();
1035#endif
1036
1037#if PLATFORM(MAC)
1038 registerDisplayConfigurationCallback();
1039#endif
1040}
1041
1042void WebProcessPool::prewarmProcess()
1043{
1044 if (m_prewarmedProcess)
1045 return;
1046
1047 RELEASE_LOG(PerformanceLogging, "Prewarming a WebProcess for performance");
1048 createNewWebProcess(nullptr, WebProcessProxy::IsPrewarmed::Yes);
1049}
1050
1051void WebProcessPool::enableProcessTermination()
1052{
1053 m_processTerminationEnabled = true;
1054 Vector<RefPtr<WebProcessProxy>> processes = m_processes;
1055 for (size_t i = 0; i < processes.size(); ++i) {
1056 if (shouldTerminate(processes[i].get()))
1057 processes[i]->terminate();
1058 }
1059}
1060
1061bool WebProcessPool::shouldTerminate(WebProcessProxy* process)
1062{
1063 ASSERT(m_processes.contains(process));
1064
1065 if (!m_processTerminationEnabled || m_configuration->alwaysKeepAndReuseSwappedProcesses())
1066 return false;
1067
1068 return true;
1069}
1070
1071void WebProcessPool::processDidFinishLaunching(WebProcessProxy* process)
1072{
1073 ASSERT(m_processes.contains(process));
1074
1075 if (!m_visitedLinksPopulated) {
1076 populateVisitedLinks();
1077 m_visitedLinksPopulated = true;
1078 }
1079
1080 // Sometimes the memorySampler gets initialized after process initialization has happened but before the process has finished launching
1081 // so check if it needs to be started here
1082 if (m_memorySamplerEnabled) {
1083 SandboxExtension::Handle sampleLogSandboxHandle;
1084 WallTime now = WallTime::now();
1085 String sampleLogFilePath = makeString("WebProcess", static_cast<unsigned long long>(now.secondsSinceEpoch().seconds()), "pid", process->processIdentifier());
1086 sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::Type::ReadWrite, sampleLogSandboxHandle);
1087
1088 process->send(Messages::WebProcess::StartMemorySampler(sampleLogSandboxHandle, sampleLogFilePath, m_memorySamplerInterval), 0);
1089 }
1090
1091 if (m_configuration->fullySynchronousModeIsAllowedForTesting())
1092 process->connection()->allowFullySynchronousModeForTesting();
1093
1094 if (m_configuration->ignoreSynchronousMessagingTimeoutsForTesting())
1095 process->connection()->ignoreTimeoutsForTesting();
1096
1097 m_connectionClient.didCreateConnection(this, process->webConnection());
1098
1099 if (m_websiteDataStore)
1100 m_websiteDataStore->websiteDataStore().didCreateNetworkProcess();
1101}
1102
1103void WebProcessPool::disconnectProcess(WebProcessProxy* process)
1104{
1105 ASSERT(m_processes.contains(process));
1106 ASSERT(!m_processesPlayingAudibleMedia.contains(process->coreProcessIdentifier()));
1107
1108 if (m_prewarmedProcess == process) {
1109 ASSERT(m_prewarmedProcess->isPrewarmed());
1110 m_prewarmedProcess = nullptr;
1111 }
1112
1113 if (m_dummyProcessProxy == process)
1114 m_dummyProcessProxy = nullptr;
1115
1116 // FIXME (Multi-WebProcess): <rdar://problem/12239765> Some of the invalidation calls of the other supplements are still necessary in multi-process mode, but they should only affect data structures pertaining to the process being disconnected.
1117 // Clearing everything causes assertion failures, so it's less trouble to skip that for now.
1118 RefPtr<WebProcessProxy> protect(process);
1119 if (m_processWithPageCache == process)
1120 m_processWithPageCache = nullptr;
1121
1122 m_suspendedPages.removeAllMatching([process](auto& suspendedPage) {
1123 return &suspendedPage->process() == process;
1124 });
1125
1126#if ENABLE(SERVICE_WORKER)
1127 if (is<ServiceWorkerProcessProxy>(*process)) {
1128 auto* removedProcess = m_serviceWorkerProcesses.take(downcast<ServiceWorkerProcessProxy>(*process).registrableDomain());
1129 ASSERT_UNUSED(removedProcess, removedProcess == process);
1130 updateProcessAssertions();
1131 }
1132#endif
1133
1134 static_cast<WebContextSupplement*>(supplement<WebGeolocationManagerProxy>())->processDidClose(process);
1135
1136 m_processes.removeFirst(process);
1137
1138#if ENABLE(GAMEPAD)
1139 if (m_processesUsingGamepads.contains(process))
1140 processStoppedUsingGamepads(*process);
1141#endif
1142
1143 removeProcessFromOriginCacheSet(*process);
1144
1145#if ENABLE(SERVICE_WORKER)
1146 // FIXME: We should do better than this. For now, we just destroy the ServiceWorker process
1147 // whenever there is no regular WebContent process remaining.
1148 if (m_processes.size() == m_serviceWorkerProcesses.size()) {
1149 if (!m_serviceWorkerProcessesTerminationTimer.isActive())
1150 m_serviceWorkerProcessesTerminationTimer.startOneShot(serviceWorkerTerminationDelay);
1151 }
1152#endif
1153}
1154
1155WebProcessProxy& WebProcessPool::processForRegistrableDomain(WebsiteDataStore& websiteDataStore, WebPageProxy* page, const RegistrableDomain& registrableDomain)
1156{
1157 if (!registrableDomain.isEmpty()) {
1158 if (auto process = webProcessCache().takeProcess(registrableDomain, websiteDataStore))
1159 return *process;
1160
1161 // Check if we have a suspended page for the given registrable domain and use its process if we do, for performance reasons.
1162 if (auto process = page ? findReusableSuspendedPageProcess(registrableDomain, *page, websiteDataStore) : nullptr) {
1163 RELEASE_LOG(ProcessSwapping, "Using WebProcess %i from a SuspendedPage", process->processIdentifier());
1164 return *process;
1165 }
1166 }
1167
1168 if (auto process = tryTakePrewarmedProcess(websiteDataStore)) {
1169 RELEASE_LOG(ProcessSwapping, "Using prewarmed process %i", process->processIdentifier());
1170 if (!registrableDomain.isEmpty())
1171 tryPrewarmWithDomainInformation(*process, registrableDomain);
1172 return *process;
1173 }
1174
1175 if (!usesSingleWebProcess())
1176 return createNewWebProcess(&websiteDataStore);
1177
1178#if PLATFORM(COCOA)
1179 bool mustMatchDataStore = API::WebsiteDataStore::defaultDataStoreExists() && &websiteDataStore != &API::WebsiteDataStore::defaultDataStore()->websiteDataStore();
1180#else
1181 bool mustMatchDataStore = false;
1182#endif
1183
1184 for (auto& process : m_processes) {
1185 if (process == m_prewarmedProcess || process == m_dummyProcessProxy)
1186 continue;
1187#if ENABLE(SERVICE_WORKER)
1188 if (is<ServiceWorkerProcessProxy>(*process))
1189 continue;
1190#endif
1191 if (mustMatchDataStore && &process->websiteDataStore() != &websiteDataStore)
1192 continue;
1193 return *process;
1194 }
1195 return createNewWebProcess(&websiteDataStore);
1196}
1197
1198Ref<WebPageProxy> WebProcessPool::createWebPage(PageClient& pageClient, Ref<API::PageConfiguration>&& pageConfiguration)
1199{
1200 if (!pageConfiguration->pageGroup())
1201 pageConfiguration->setPageGroup(m_defaultPageGroup.ptr());
1202 if (!pageConfiguration->preferences())
1203 pageConfiguration->setPreferences(&pageConfiguration->pageGroup()->preferences());
1204 if (!pageConfiguration->userContentController())
1205 pageConfiguration->setUserContentController(&pageConfiguration->pageGroup()->userContentController());
1206 if (!pageConfiguration->visitedLinkStore())
1207 pageConfiguration->setVisitedLinkStore(m_visitedLinkStore.ptr());
1208
1209 if (!pageConfiguration->websiteDataStore()) {
1210 // We try to avoid creating the default data store as long as possible.
1211 // But if there is an attempt to create a web page without any specified data store, then we have to create it.
1212 if (!m_websiteDataStore)
1213 m_websiteDataStore = API::WebsiteDataStore::defaultDataStore().ptr();
1214
1215 ASSERT(!pageConfiguration->sessionID().isValid());
1216 pageConfiguration->setWebsiteDataStore(m_websiteDataStore.get());
1217 pageConfiguration->setSessionID(pageConfiguration->preferences()->privateBrowsingEnabled() ? PAL::SessionID::legacyPrivateSessionID() : m_websiteDataStore->websiteDataStore().sessionID());
1218 }
1219
1220 RefPtr<WebProcessProxy> process;
1221 auto* relatedPage = pageConfiguration->relatedPage();
1222 if (relatedPage && !relatedPage->isClosed()) {
1223 // Sharing processes, e.g. when creating the page via window.open().
1224 process = &pageConfiguration->relatedPage()->ensureRunningProcess();
1225 // We do not support several WebsiteDataStores sharing a single process.
1226 ASSERT(process.get() == m_dummyProcessProxy || &pageConfiguration->websiteDataStore()->websiteDataStore() == &process->websiteDataStore());
1227 ASSERT(&pageConfiguration->relatedPage()->websiteDataStore() == &pageConfiguration->websiteDataStore()->websiteDataStore());
1228 } else if (!m_isDelayedWebProcessLaunchDisabled) {
1229 // In the common case, we delay process launch until something is actually loaded in the page.
1230 if (!m_dummyProcessProxy) {
1231 auto dummyProcessProxy = WebProcessProxy::create(*this, nullptr, WebProcessProxy::IsPrewarmed::No, WebProcessProxy::ShouldLaunchProcess::No);
1232 m_dummyProcessProxy = dummyProcessProxy.ptr();
1233 m_processes.append(WTFMove(dummyProcessProxy));
1234 }
1235 process = m_dummyProcessProxy;
1236 } else
1237 process = &processForRegistrableDomain(pageConfiguration->websiteDataStore()->websiteDataStore(), nullptr, { });
1238
1239 ASSERT(process);
1240
1241 auto page = process->createWebPage(pageClient, WTFMove(pageConfiguration));
1242
1243#if ENABLE(SERVICE_WORKER)
1244 ASSERT(!is<ServiceWorkerProcessProxy>(*process));
1245
1246 if (!m_serviceWorkerPreferences) {
1247 m_serviceWorkerPreferences = page->preferencesStore();
1248 for (auto* serviceWorkerProcess : m_serviceWorkerProcesses.values())
1249 serviceWorkerProcess->updatePreferencesStore(*m_serviceWorkerPreferences);
1250 }
1251#endif
1252
1253 bool enableProcessSwapOnCrossSiteNavigation = page->preferences().processSwapOnCrossSiteNavigationEnabled();
1254#if PLATFORM(IOS_FAMILY)
1255 if (WebCore::IOSApplication::isFirefox() && !linkedOnOrAfter(WebKit::SDKVersion::FirstWithProcessSwapOnCrossSiteNavigation))
1256 enableProcessSwapOnCrossSiteNavigation = false;
1257#endif
1258
1259 bool wasProcessSwappingOnNavigationEnabled = m_configuration->processSwapsOnNavigation();
1260 m_configuration->setProcessSwapsOnNavigationFromExperimentalFeatures(enableProcessSwapOnCrossSiteNavigation);
1261 if (wasProcessSwappingOnNavigationEnabled != m_configuration->processSwapsOnNavigation())
1262 m_webProcessCache->updateCapacity(*this);
1263
1264 m_configuration->setShouldCaptureAudioInUIProcess(page->preferences().captureAudioInUIProcessEnabled());
1265 m_configuration->setShouldCaptureVideoInUIProcess(page->preferences().captureVideoInUIProcessEnabled());
1266
1267 return page;
1268}
1269
1270#if ENABLE(SERVICE_WORKER)
1271void WebProcessPool::updateServiceWorkerUserAgent(const String& userAgent)
1272{
1273 if (m_serviceWorkerUserAgent == userAgent)
1274 return;
1275 m_serviceWorkerUserAgent = userAgent;
1276 for (auto* serviceWorkerProcess : m_serviceWorkerProcesses.values())
1277 serviceWorkerProcess->setUserAgent(m_serviceWorkerUserAgent);
1278}
1279
1280bool WebProcessPool::mayHaveRegisteredServiceWorkers(const WebsiteDataStore& store)
1281{
1282 if (!m_serviceWorkerProcesses.isEmpty())
1283 return true;
1284
1285 String serviceWorkerRegistrationDirectory = store.resolvedServiceWorkerRegistrationDirectory();
1286 if (serviceWorkerRegistrationDirectory.isEmpty())
1287 serviceWorkerRegistrationDirectory = API::WebsiteDataStore::defaultDataStoreConfiguration()->serviceWorkerRegistrationDirectory();
1288
1289 return m_mayHaveRegisteredServiceWorkers.ensure(serviceWorkerRegistrationDirectory, [&] {
1290 // FIXME: Make this computation on a background thread.
1291 return ServiceWorkerProcessProxy::hasRegisteredServiceWorkers(serviceWorkerRegistrationDirectory);
1292 }).iterator->value;
1293}
1294#endif
1295
1296void WebProcessPool::pageBeginUsingWebsiteDataStore(PageIdentifier pageID, WebsiteDataStore& dataStore)
1297{
1298 auto result = m_sessionToPageIDsMap.add(dataStore.sessionID(), HashSet<PageIdentifier>()).iterator->value.add(pageID);
1299 ASSERT_UNUSED(result, result.isNewEntry);
1300
1301 auto sessionID = dataStore.sessionID();
1302 if (sessionID.isEphemeral()) {
1303 ASSERT(dataStore.parameters().networkSessionParameters.sessionID == sessionID);
1304 if (m_networkProcess) {
1305 m_networkProcess->addSession(makeRef(dataStore));
1306 dataStore.clearPendingCookies();
1307 }
1308 } else if (sessionID != PAL::SessionID::defaultSessionID()) {
1309 if (m_networkProcess) {
1310 m_networkProcess->addSession(makeRef(dataStore));
1311 dataStore.clearPendingCookies();
1312 }
1313 }
1314}
1315
1316void WebProcessPool::pageEndUsingWebsiteDataStore(PageIdentifier pageID, WebsiteDataStore& dataStore)
1317{
1318 auto sessionID = dataStore.sessionID();
1319 auto iterator = m_sessionToPageIDsMap.find(sessionID);
1320 ASSERT(iterator != m_sessionToPageIDsMap.end());
1321
1322 auto takenPageID = iterator->value.take(pageID);
1323 ASSERT_UNUSED(takenPageID, takenPageID == pageID);
1324
1325 if (iterator->value.isEmpty()) {
1326 m_sessionToPageIDsMap.remove(iterator);
1327
1328 if (sessionID == PAL::SessionID::defaultSessionID())
1329 return;
1330
1331 // The last user of this non-default PAL::SessionID is gone, so clean it up in the child processes.
1332 if (networkProcess())
1333 networkProcess()->removeSession(sessionID);
1334
1335 m_webProcessCache->clearAllProcessesForSession(sessionID);
1336 }
1337}
1338
1339bool WebProcessPool::hasPagesUsingWebsiteDataStore(WebsiteDataStore& dataStore) const
1340{
1341 return m_sessionToPageIDsMap.contains(dataStore.sessionID());
1342}
1343
1344DownloadProxy& WebProcessPool::download(WebPageProxy* initiatingPage, const ResourceRequest& request, const String& suggestedFilename)
1345{
1346 auto& downloadProxy = createDownloadProxy(request, initiatingPage);
1347 PAL::SessionID sessionID = initiatingPage ? initiatingPage->sessionID() : PAL::SessionID::defaultSessionID();
1348
1349 if (initiatingPage)
1350 initiatingPage->handleDownloadRequest(downloadProxy);
1351
1352 if (networkProcess()) {
1353 ResourceRequest updatedRequest(request);
1354 // Request's firstPartyForCookies will be used as Original URL of the download request.
1355 // We set the value to top level document's URL.
1356 if (initiatingPage) {
1357 URL initiatingPageURL = URL { URL { }, initiatingPage->pageLoadState().url() };
1358 updatedRequest.setFirstPartyForCookies(initiatingPageURL);
1359 updatedRequest.setIsSameSite(areRegistrableDomainsEqual(initiatingPageURL, request.url()));
1360 if (!updatedRequest.hasHTTPHeaderField(HTTPHeaderName::UserAgent))
1361 updatedRequest.setHTTPUserAgent(initiatingPage->userAgent());
1362 } else {
1363 updatedRequest.setFirstPartyForCookies(URL());
1364 updatedRequest.setIsSameSite(false);
1365 if (!updatedRequest.hasHTTPHeaderField(HTTPHeaderName::UserAgent))
1366 updatedRequest.setHTTPUserAgent(WebPageProxy::standardUserAgent());
1367 }
1368 updatedRequest.setIsTopSite(false);
1369 networkProcess()->send(Messages::NetworkProcess::DownloadRequest(sessionID, downloadProxy.downloadID(), updatedRequest, suggestedFilename), 0);
1370 return downloadProxy;
1371 }
1372
1373 return downloadProxy;
1374}
1375
1376DownloadProxy& WebProcessPool::resumeDownload(WebPageProxy* initiatingPage, const API::Data* resumeData, const String& path)
1377{
1378 auto& downloadProxy = createDownloadProxy(ResourceRequest(), initiatingPage);
1379 PAL::SessionID sessionID = initiatingPage ? initiatingPage->sessionID() : PAL::SessionID::defaultSessionID();
1380
1381 SandboxExtension::Handle sandboxExtensionHandle;
1382 if (!path.isEmpty())
1383 SandboxExtension::createHandle(path, SandboxExtension::Type::ReadWrite, sandboxExtensionHandle);
1384
1385 if (networkProcess()) {
1386 networkProcess()->send(Messages::NetworkProcess::ResumeDownload(sessionID, downloadProxy.downloadID(), resumeData->dataReference(), path, sandboxExtensionHandle), 0);
1387 return downloadProxy;
1388 }
1389
1390 return downloadProxy;
1391}
1392
1393void WebProcessPool::postMessageToInjectedBundle(const String& messageName, API::Object* messageBody)
1394{
1395 for (auto& process : m_processes) {
1396 // FIXME: Return early if the message body contains any references to WKPageRefs/WKFrameRefs etc. since they're local to a process.
1397 process->send(Messages::WebProcess::HandleInjectedBundleMessage(messageName, UserData(process->transformObjectsToHandles(messageBody).get())), 0);
1398 }
1399}
1400
1401void WebProcessPool::didReachGoodTimeToPrewarm()
1402{
1403 if (!configuration().isAutomaticProcessWarmingEnabled() || !configuration().processSwapsOnNavigation() || usesSingleWebProcess())
1404 return;
1405
1406 if (MemoryPressureHandler::singleton().isUnderMemoryPressure()) {
1407 if (!m_prewarmedProcess)
1408 RELEASE_LOG(PerformanceLogging, "Not automatically prewarming a WebProcess due to memory pressure");
1409 return;
1410 }
1411
1412 prewarmProcess();
1413}
1414
1415void WebProcessPool::populateVisitedLinks()
1416{
1417 m_historyClient->populateVisitedLinks(*this);
1418}
1419
1420WebProcessPool::Statistics& WebProcessPool::statistics()
1421{
1422 static Statistics statistics = Statistics();
1423
1424 return statistics;
1425}
1426
1427void WebProcessPool::handleMemoryPressureWarning(Critical)
1428{
1429 RELEASE_LOG(PerformanceLogging, "%p - WebProcessPool::handleMemoryPressureWarning", this);
1430
1431
1432 clearSuspendedPages(AllowProcessCaching::No);
1433 m_webProcessCache->clear();
1434
1435 if (m_prewarmedProcess)
1436 m_prewarmedProcess->shutDown();
1437 ASSERT(!m_prewarmedProcess);
1438}
1439
1440#if ENABLE(NETSCAPE_PLUGIN_API)
1441void WebProcessPool::setAdditionalPluginsDirectory(const String& directory)
1442{
1443 Vector<String> directories;
1444 directories.append(directory);
1445
1446 m_pluginInfoStore.setAdditionalPluginsDirectories(directories);
1447}
1448
1449void WebProcessPool::refreshPlugins()
1450{
1451 m_pluginInfoStore.refresh();
1452 sendToAllProcesses(Messages::WebProcess::RefreshPlugins());
1453}
1454
1455#endif // ENABLE(NETSCAPE_PLUGIN_API)
1456
1457ProcessID WebProcessPool::networkProcessIdentifier()
1458{
1459 return m_networkProcess ? m_networkProcess->processIdentifier() : 0;
1460}
1461
1462ProcessID WebProcessPool::prewarmedProcessIdentifier()
1463{
1464 return m_prewarmedProcess ? m_prewarmedProcess->processIdentifier() : 0;
1465}
1466
1467void WebProcessPool::activePagesOriginsInWebProcessForTesting(ProcessID pid, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
1468{
1469 for (auto& process : m_processes) {
1470 if (process->processIdentifier() == pid)
1471 return process->activePagesDomainsForTesting(WTFMove(completionHandler));
1472 }
1473 completionHandler({ });
1474}
1475
1476void WebProcessPool::setAlwaysUsesComplexTextCodePath(bool alwaysUseComplexText)
1477{
1478 m_alwaysUsesComplexTextCodePath = alwaysUseComplexText;
1479 sendToAllProcesses(Messages::WebProcess::SetAlwaysUsesComplexTextCodePath(alwaysUseComplexText));
1480}
1481
1482void WebProcessPool::setShouldUseFontSmoothing(bool useFontSmoothing)
1483{
1484 m_shouldUseFontSmoothing = useFontSmoothing;
1485 sendToAllProcesses(Messages::WebProcess::SetShouldUseFontSmoothing(useFontSmoothing));
1486}
1487
1488void WebProcessPool::setResourceLoadStatisticsEnabled(bool enabled)
1489{
1490 sendToAllProcesses(Messages::WebProcess::SetResourceLoadStatisticsEnabled(enabled));
1491#if ENABLE(RESOURCE_LOAD_STATISTICS)
1492 sendToNetworkingProcess(Messages::NetworkProcess::SetResourceLoadStatisticsEnabled(enabled));
1493#endif
1494}
1495
1496void WebProcessPool::clearResourceLoadStatistics()
1497{
1498 sendToAllProcesses(Messages::WebProcess::ClearResourceLoadStatistics());
1499}
1500
1501void WebProcessPool::registerURLSchemeAsEmptyDocument(const String& urlScheme)
1502{
1503 m_schemesToRegisterAsEmptyDocument.add(urlScheme);
1504 sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsEmptyDocument(urlScheme));
1505}
1506
1507void WebProcessPool::registerURLSchemeAsSecure(const String& urlScheme)
1508{
1509 m_schemesToRegisterAsSecure.add(urlScheme);
1510 sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsSecure(urlScheme));
1511 sendToNetworkingProcess(Messages::NetworkProcess::RegisterURLSchemeAsSecure(urlScheme));
1512}
1513
1514void WebProcessPool::registerURLSchemeAsBypassingContentSecurityPolicy(const String& urlScheme)
1515{
1516 m_schemesToRegisterAsBypassingContentSecurityPolicy.add(urlScheme);
1517 sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsBypassingContentSecurityPolicy(urlScheme));
1518 sendToNetworkingProcess(Messages::NetworkProcess::RegisterURLSchemeAsBypassingContentSecurityPolicy(urlScheme));
1519}
1520
1521void WebProcessPool::setDomainRelaxationForbiddenForURLScheme(const String& urlScheme)
1522{
1523 m_schemesToSetDomainRelaxationForbiddenFor.add(urlScheme);
1524 sendToAllProcesses(Messages::WebProcess::SetDomainRelaxationForbiddenForURLScheme(urlScheme));
1525}
1526
1527void WebProcessPool::setCanHandleHTTPSServerTrustEvaluation(bool value)
1528{
1529 m_canHandleHTTPSServerTrustEvaluation = value;
1530 if (m_networkProcess) {
1531 m_networkProcess->send(Messages::NetworkProcess::SetCanHandleHTTPSServerTrustEvaluation(value), 0);
1532 return;
1533 }
1534}
1535
1536void WebProcessPool::preconnectToServer(const URL& url)
1537{
1538 if (!url.isValid() || !url.protocolIsInHTTPFamily())
1539 return;
1540
1541 ensureNetworkProcess().send(Messages::NetworkProcess::PreconnectTo(url, StoredCredentialsPolicy::Use), 0);
1542}
1543
1544void WebProcessPool::registerURLSchemeAsLocal(const String& urlScheme)
1545{
1546 m_schemesToRegisterAsLocal.add(urlScheme);
1547 sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsLocal(urlScheme));
1548 sendToNetworkingProcess(Messages::NetworkProcess::RegisterURLSchemeAsLocal(urlScheme));
1549}
1550
1551void WebProcessPool::registerURLSchemeAsNoAccess(const String& urlScheme)
1552{
1553 m_schemesToRegisterAsNoAccess.add(urlScheme);
1554 sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsNoAccess(urlScheme));
1555 sendToNetworkingProcess(Messages::NetworkProcess::RegisterURLSchemeAsNoAccess(urlScheme));
1556}
1557
1558void WebProcessPool::registerURLSchemeAsDisplayIsolated(const String& urlScheme)
1559{
1560 m_schemesToRegisterAsDisplayIsolated.add(urlScheme);
1561 sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsDisplayIsolated(urlScheme));
1562 sendToNetworkingProcess(Messages::NetworkProcess::RegisterURLSchemeAsDisplayIsolated(urlScheme));
1563}
1564
1565void WebProcessPool::registerURLSchemeAsCORSEnabled(const String& urlScheme)
1566{
1567 m_schemesToRegisterAsCORSEnabled.add(urlScheme);
1568 sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsCORSEnabled(urlScheme));
1569 sendToNetworkingProcess(Messages::NetworkProcess::RegisterURLSchemeAsCORSEnabled(urlScheme));
1570}
1571
1572void WebProcessPool::registerGlobalURLSchemeAsHavingCustomProtocolHandlers(const String& urlScheme)
1573{
1574 if (!urlScheme)
1575 return;
1576
1577 globalURLSchemesWithCustomProtocolHandlers().add(urlScheme);
1578 for (auto* processPool : allProcessPools())
1579 processPool->registerSchemeForCustomProtocol(urlScheme);
1580}
1581
1582void WebProcessPool::unregisterGlobalURLSchemeAsHavingCustomProtocolHandlers(const String& urlScheme)
1583{
1584 if (!urlScheme)
1585 return;
1586
1587 globalURLSchemesWithCustomProtocolHandlers().remove(urlScheme);
1588 for (auto* processPool : allProcessPools())
1589 processPool->unregisterSchemeForCustomProtocol(urlScheme);
1590}
1591
1592void WebProcessPool::registerURLSchemeAsCachePartitioned(const String& urlScheme)
1593{
1594 m_schemesToRegisterAsCachePartitioned.add(urlScheme);
1595 sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsCachePartitioned(urlScheme));
1596}
1597
1598void WebProcessPool::registerURLSchemeServiceWorkersCanHandle(const String& urlScheme)
1599{
1600 m_schemesServiceWorkersCanHandle.add(urlScheme);
1601 sendToAllProcesses(Messages::AuxiliaryProcess::RegisterURLSchemeServiceWorkersCanHandle(urlScheme));
1602 if (m_networkProcess)
1603 m_networkProcess->send(Messages::AuxiliaryProcess::RegisterURLSchemeServiceWorkersCanHandle(urlScheme), 0);
1604}
1605
1606void WebProcessPool::registerURLSchemeAsCanDisplayOnlyIfCanRequest(const String& urlScheme)
1607{
1608 m_schemesToRegisterAsCanDisplayOnlyIfCanRequest.add(urlScheme);
1609 sendToAllProcesses(Messages::WebProcess::RegisterURLSchemeAsCanDisplayOnlyIfCanRequest(urlScheme));
1610 sendToNetworkingProcess(Messages::NetworkProcess::RegisterURLSchemeAsCanDisplayOnlyIfCanRequest(urlScheme));
1611}
1612
1613void WebProcessPool::updateMaxSuspendedPageCount()
1614{
1615 unsigned dummy = 0;
1616 Seconds dummyInterval;
1617 unsigned pageCacheSize = 0;
1618 calculateMemoryCacheSizes(m_configuration->cacheModel(), dummy, dummy, dummy, dummyInterval, pageCacheSize);
1619
1620 m_maxSuspendedPageCount = pageCacheSize;
1621
1622 while (m_suspendedPages.size() > m_maxSuspendedPageCount)
1623 m_suspendedPages.removeFirst();
1624}
1625
1626void WebProcessPool::setCacheModel(CacheModel cacheModel)
1627{
1628 m_configuration->setCacheModel(cacheModel);
1629 updateMaxSuspendedPageCount();
1630
1631 sendToAllProcesses(Messages::WebProcess::SetCacheModel(cacheModel));
1632
1633 if (m_networkProcess)
1634 m_networkProcess->send(Messages::NetworkProcess::SetCacheModel(cacheModel), 0);
1635}
1636
1637void WebProcessPool::setDefaultRequestTimeoutInterval(double timeoutInterval)
1638{
1639 sendToAllProcesses(Messages::WebProcess::SetDefaultRequestTimeoutInterval(timeoutInterval));
1640}
1641
1642DownloadProxy& WebProcessPool::createDownloadProxy(const ResourceRequest& request, WebPageProxy* originatingPage)
1643{
1644 auto& downloadProxy = ensureNetworkProcess().createDownloadProxy(request);
1645 downloadProxy.setOriginatingPage(originatingPage);
1646 return downloadProxy;
1647}
1648
1649void WebProcessPool::synthesizeAppIsBackground(bool background)
1650{
1651 ensureNetworkProcess().synthesizeAppIsBackground(background);
1652}
1653
1654void WebProcessPool::addMessageReceiver(IPC::StringReference messageReceiverName, IPC::MessageReceiver& messageReceiver)
1655{
1656 m_messageReceiverMap.addMessageReceiver(messageReceiverName, messageReceiver);
1657}
1658
1659void WebProcessPool::addMessageReceiver(IPC::StringReference messageReceiverName, uint64_t destinationID, IPC::MessageReceiver& messageReceiver)
1660{
1661 m_messageReceiverMap.addMessageReceiver(messageReceiverName, destinationID, messageReceiver);
1662}
1663
1664void WebProcessPool::removeMessageReceiver(IPC::StringReference messageReceiverName)
1665{
1666 m_messageReceiverMap.removeMessageReceiver(messageReceiverName);
1667}
1668
1669void WebProcessPool::removeMessageReceiver(IPC::StringReference messageReceiverName, uint64_t destinationID)
1670{
1671 m_messageReceiverMap.removeMessageReceiver(messageReceiverName, destinationID);
1672}
1673
1674bool WebProcessPool::dispatchMessage(IPC::Connection& connection, IPC::Decoder& decoder)
1675{
1676 return m_messageReceiverMap.dispatchMessage(connection, decoder);
1677}
1678
1679bool WebProcessPool::dispatchSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& replyEncoder)
1680{
1681 return m_messageReceiverMap.dispatchSyncMessage(connection, decoder, replyEncoder);
1682}
1683
1684void WebProcessPool::setEnhancedAccessibility(bool flag)
1685{
1686 sendToAllProcesses(Messages::WebProcess::SetEnhancedAccessibility(flag));
1687}
1688
1689void WebProcessPool::startMemorySampler(const double interval)
1690{
1691 // For new WebProcesses we will also want to start the Memory Sampler
1692 m_memorySamplerEnabled = true;
1693 m_memorySamplerInterval = interval;
1694
1695 // For UIProcess
1696#if ENABLE(MEMORY_SAMPLER)
1697 WebMemorySampler::singleton()->start(interval);
1698#endif
1699
1700 // For WebProcess
1701 SandboxExtension::Handle sampleLogSandboxHandle;
1702 WallTime now = WallTime::now();
1703 String sampleLogFilePath = makeString("WebProcess", static_cast<unsigned long long>(now.secondsSinceEpoch().seconds()));
1704 sampleLogFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::Type::ReadWrite, sampleLogSandboxHandle);
1705
1706 sendToAllProcesses(Messages::WebProcess::StartMemorySampler(sampleLogSandboxHandle, sampleLogFilePath, interval));
1707}
1708
1709void WebProcessPool::stopMemorySampler()
1710{
1711 // For WebProcess
1712 m_memorySamplerEnabled = false;
1713
1714 // For UIProcess
1715#if ENABLE(MEMORY_SAMPLER)
1716 WebMemorySampler::singleton()->stop();
1717#endif
1718
1719 sendToAllProcesses(Messages::WebProcess::StopMemorySampler());
1720}
1721
1722void WebProcessPool::useTestingNetworkSession()
1723{
1724 ASSERT(m_processes.isEmpty());
1725 ASSERT(!m_networkProcess);
1726
1727 if (m_networkProcess)
1728 return;
1729
1730 if (!m_processes.isEmpty())
1731 return;
1732
1733 m_shouldUseTestingNetworkSession = true;
1734}
1735
1736template<typename T, typename U>
1737void WebProcessPool::sendSyncToNetworkingProcess(T&& message, U&& reply)
1738{
1739 if (m_networkProcess && m_networkProcess->canSendMessage())
1740 m_networkProcess->sendSync(std::forward<T>(message), std::forward<U>(reply), 0);
1741}
1742
1743void WebProcessPool::setAllowsAnySSLCertificateForWebSocket(bool allows)
1744{
1745 sendSyncToNetworkingProcess(Messages::NetworkProcess::SetAllowsAnySSLCertificateForWebSocket(allows), Messages::NetworkProcess::SetAllowsAnySSLCertificateForWebSocket::Reply());
1746}
1747
1748void WebProcessPool::clearCachedCredentials()
1749{
1750 if (m_networkProcess)
1751 m_networkProcess->send(Messages::NetworkProcess::ClearCachedCredentials(), 0);
1752}
1753
1754void WebProcessPool::terminateNetworkProcess()
1755{
1756 if (!m_networkProcess)
1757 return;
1758
1759 m_networkProcess->terminate();
1760 m_networkProcess = nullptr;
1761 m_didNetworkProcessCrash = true;
1762}
1763
1764void WebProcessPool::sendNetworkProcessWillSuspendImminently()
1765{
1766 if (m_networkProcess)
1767 m_networkProcess->sendProcessWillSuspendImminently();
1768}
1769
1770void WebProcessPool::sendNetworkProcessDidResume()
1771{
1772 if (m_networkProcess)
1773 m_networkProcess->sendProcessDidResume();
1774}
1775
1776void WebProcessPool::terminateServiceWorkerProcesses()
1777{
1778#if ENABLE(SERVICE_WORKER)
1779 auto protectedThis = makeRef(*this);
1780 while (!m_serviceWorkerProcesses.isEmpty())
1781 m_serviceWorkerProcesses.begin()->value->requestTermination(ProcessTerminationReason::RequestedByClient);
1782#endif
1783}
1784
1785void WebProcessPool::syncNetworkProcessCookies()
1786{
1787 ensureNetworkProcess().syncAllCookies();
1788}
1789
1790void WebProcessPool::setIDBPerOriginQuota(uint64_t quota)
1791{
1792#if ENABLE(INDEXED_DATABASE)
1793 ensureNetworkProcess().send(Messages::NetworkProcess::SetIDBPerOriginQuota(quota), 0);
1794#endif
1795}
1796
1797void WebProcessPool::allowSpecificHTTPSCertificateForHost(const WebCertificateInfo* certificate, const String& host)
1798{
1799 ensureNetworkProcess();
1800 m_networkProcess->send(Messages::NetworkProcess::AllowSpecificHTTPSCertificateForHost(certificate->certificateInfo(), host), 0);
1801}
1802
1803void WebProcessPool::updateAutomationCapabilities() const
1804{
1805#if ENABLE(REMOTE_INSPECTOR)
1806 Inspector::RemoteInspector::singleton().clientCapabilitiesDidChange();
1807#endif
1808}
1809
1810void WebProcessPool::setAutomationSession(RefPtr<WebAutomationSession>&& automationSession)
1811{
1812 if (m_automationSession)
1813 m_automationSession->setProcessPool(nullptr);
1814
1815 m_automationSession = WTFMove(automationSession);
1816
1817#if ENABLE(REMOTE_INSPECTOR)
1818 if (m_automationSession) {
1819 m_automationSession->init();
1820 m_automationSession->setProcessPool(this);
1821
1822 sendToAllProcesses(Messages::WebProcess::EnsureAutomationSessionProxy(m_automationSession->sessionIdentifier()));
1823 } else
1824 sendToAllProcesses(Messages::WebProcess::DestroyAutomationSessionProxy());
1825#endif
1826}
1827
1828void WebProcessPool::setHTTPPipeliningEnabled(bool enabled)
1829{
1830#if PLATFORM(COCOA)
1831 ResourceRequest::setHTTPPipeliningEnabled(enabled);
1832#else
1833 UNUSED_PARAM(enabled);
1834#endif
1835}
1836
1837bool WebProcessPool::httpPipeliningEnabled() const
1838{
1839#if PLATFORM(COCOA)
1840 return ResourceRequest::httpPipeliningEnabled();
1841#else
1842 return false;
1843#endif
1844}
1845
1846void WebProcessPool::getStatistics(uint32_t statisticsMask, Function<void (API::Dictionary*, CallbackBase::Error)>&& callbackFunction)
1847{
1848 if (!statisticsMask) {
1849 callbackFunction(nullptr, CallbackBase::Error::Unknown);
1850 return;
1851 }
1852
1853 auto request = StatisticsRequest::create(DictionaryCallback::create(WTFMove(callbackFunction)));
1854
1855 if (statisticsMask & StatisticsRequestTypeWebContent)
1856 requestWebContentStatistics(request.get());
1857
1858 if (statisticsMask & StatisticsRequestTypeNetworking)
1859 requestNetworkingStatistics(request.get());
1860}
1861
1862void WebProcessPool::requestWebContentStatistics(StatisticsRequest& request)
1863{
1864 // FIXME (Multi-WebProcess) <rdar://problem/13200059>: Make getting statistics from multiple WebProcesses work.
1865}
1866
1867void WebProcessPool::requestNetworkingStatistics(StatisticsRequest& request)
1868{
1869 if (!m_networkProcess) {
1870 LOG_ERROR("Attempt to get NetworkProcess statistics but the NetworkProcess is unavailable");
1871 return;
1872 }
1873
1874 uint64_t requestID = request.addOutstandingRequest();
1875 m_statisticsRequests.set(requestID, &request);
1876 m_networkProcess->send(Messages::NetworkProcess::GetNetworkProcessStatistics(requestID), 0);
1877}
1878
1879static WebProcessProxy* webProcessProxyFromConnection(IPC::Connection& connection, const Vector<RefPtr<WebProcessProxy>>& processes)
1880{
1881 for (auto& process : processes) {
1882 if (process->hasConnection(connection))
1883 return process.get();
1884 }
1885
1886 ASSERT_NOT_REACHED();
1887 return nullptr;
1888}
1889
1890void WebProcessPool::handleMessage(IPC::Connection& connection, const String& messageName, const WebKit::UserData& messageBody)
1891{
1892 auto* webProcessProxy = webProcessProxyFromConnection(connection, m_processes);
1893 if (!webProcessProxy)
1894 return;
1895 m_injectedBundleClient->didReceiveMessageFromInjectedBundle(*this, messageName, webProcessProxy->transformHandlesToObjects(messageBody.object()).get());
1896}
1897
1898void WebProcessPool::handleSynchronousMessage(IPC::Connection& connection, const String& messageName, const UserData& messageBody, CompletionHandler<void(UserData&&)>&& completionHandler)
1899{
1900 auto* webProcessProxy = webProcessProxyFromConnection(connection, m_processes);
1901 if (!webProcessProxy)
1902 return completionHandler({ });
1903
1904 RefPtr<API::Object> returnData;
1905 m_injectedBundleClient->didReceiveSynchronousMessageFromInjectedBundle(*this, messageName, webProcessProxy->transformHandlesToObjects(messageBody.object()).get(), returnData);
1906 completionHandler(UserData(webProcessProxy->transformObjectsToHandles(returnData.get())));
1907}
1908
1909void WebProcessPool::didGetStatistics(const StatisticsData& statisticsData, uint64_t requestID)
1910{
1911 RefPtr<StatisticsRequest> request = m_statisticsRequests.take(requestID);
1912 if (!request) {
1913 LOG_ERROR("Cannot report networking statistics.");
1914 return;
1915 }
1916
1917 request->completedRequest(requestID, statisticsData);
1918}
1919
1920#if ENABLE(GAMEPAD)
1921
1922void WebProcessPool::startedUsingGamepads(IPC::Connection& connection)
1923{
1924 auto* proxy = webProcessProxyFromConnection(connection, m_processes);
1925 if (!proxy)
1926 return;
1927
1928 bool wereAnyProcessesUsingGamepads = !m_processesUsingGamepads.isEmpty();
1929
1930 ASSERT(!m_processesUsingGamepads.contains(proxy));
1931 m_processesUsingGamepads.add(proxy);
1932
1933 if (!wereAnyProcessesUsingGamepads)
1934 UIGamepadProvider::singleton().processPoolStartedUsingGamepads(*this);
1935
1936 proxy->send(Messages::WebProcess::SetInitialGamepads(UIGamepadProvider::singleton().snapshotGamepads()), 0);
1937}
1938
1939void WebProcessPool::stoppedUsingGamepads(IPC::Connection& connection)
1940{
1941 auto* proxy = webProcessProxyFromConnection(connection, m_processes);
1942 if (!proxy)
1943 return;
1944
1945 ASSERT(m_processesUsingGamepads.contains(proxy));
1946 processStoppedUsingGamepads(*proxy);
1947}
1948
1949void WebProcessPool::processStoppedUsingGamepads(WebProcessProxy& process)
1950{
1951 bool wereAnyProcessesUsingGamepads = !m_processesUsingGamepads.isEmpty();
1952
1953 ASSERT(m_processesUsingGamepads.contains(&process));
1954 m_processesUsingGamepads.remove(&process);
1955
1956 if (wereAnyProcessesUsingGamepads && m_processesUsingGamepads.isEmpty())
1957 UIGamepadProvider::singleton().processPoolStoppedUsingGamepads(*this);
1958}
1959
1960void WebProcessPool::gamepadConnected(const UIGamepad& gamepad)
1961{
1962 for (auto& process : m_processesUsingGamepads)
1963 process->send(Messages::WebProcess::GamepadConnected(gamepad.fullGamepadData()), 0);
1964}
1965
1966void WebProcessPool::gamepadDisconnected(const UIGamepad& gamepad)
1967{
1968 for (auto& process : m_processesUsingGamepads)
1969 process->send(Messages::WebProcess::GamepadDisconnected(gamepad.index()), 0);
1970}
1971
1972void WebProcessPool::setInitialConnectedGamepads(const Vector<std::unique_ptr<UIGamepad>>& gamepads)
1973{
1974 Vector<GamepadData> gamepadDatas;
1975 gamepadDatas.grow(gamepads.size());
1976 for (size_t i = 0; i < gamepads.size(); ++i) {
1977 if (!gamepads[i])
1978 continue;
1979 gamepadDatas[i] = gamepads[i]->fullGamepadData();
1980 }
1981
1982 for (auto& process : m_processesUsingGamepads)
1983 process->send(Messages::WebProcess::SetInitialGamepads(gamepadDatas), 0);
1984}
1985
1986#endif // ENABLE(GAMEPAD)
1987
1988void WebProcessPool::setJavaScriptConfigurationFileEnabled(bool flag)
1989{
1990 m_javaScriptConfigurationFileEnabled = flag;
1991}
1992
1993void WebProcessPool::garbageCollectJavaScriptObjects()
1994{
1995 sendToAllProcesses(Messages::WebProcess::GarbageCollectJavaScriptObjects());
1996}
1997
1998void WebProcessPool::setJavaScriptGarbageCollectorTimerEnabled(bool flag)
1999{
2000 sendToAllProcesses(Messages::WebProcess::SetJavaScriptGarbageCollectorTimerEnabled(flag));
2001}
2002
2003void WebProcessPool::addPlugInAutoStartOriginHash(const String& pageOrigin, unsigned plugInOriginHash, PAL::SessionID sessionID)
2004{
2005 m_plugInAutoStartProvider.addAutoStartOriginHash(pageOrigin, plugInOriginHash, sessionID);
2006}
2007
2008void WebProcessPool::plugInDidReceiveUserInteraction(unsigned plugInOriginHash, PAL::SessionID sessionID)
2009{
2010 m_plugInAutoStartProvider.didReceiveUserInteraction(plugInOriginHash, sessionID);
2011}
2012
2013Ref<API::Dictionary> WebProcessPool::plugInAutoStartOriginHashes() const
2014{
2015 return m_plugInAutoStartProvider.autoStartOriginsTableCopy();
2016}
2017
2018void WebProcessPool::setPlugInAutoStartOriginHashes(API::Dictionary& dictionary)
2019{
2020 m_plugInAutoStartProvider.setAutoStartOriginsTable(dictionary);
2021}
2022
2023void WebProcessPool::setPlugInAutoStartOrigins(API::Array& array)
2024{
2025 m_plugInAutoStartProvider.setAutoStartOriginsArray(array);
2026}
2027
2028void WebProcessPool::setPlugInAutoStartOriginsFilteringOutEntriesAddedAfterTime(API::Dictionary& dictionary, WallTime time)
2029{
2030 m_plugInAutoStartProvider.setAutoStartOriginsFilteringOutEntriesAddedAfterTime(dictionary, time);
2031}
2032
2033void WebProcessPool::registerSchemeForCustomProtocol(const String& scheme)
2034{
2035#if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER)
2036 if (!globalURLSchemesWithCustomProtocolHandlers().contains(scheme))
2037 m_urlSchemesRegisteredForCustomProtocols.add(scheme);
2038 sendToNetworkingProcess(Messages::LegacyCustomProtocolManager::RegisterScheme(scheme));
2039#endif
2040}
2041
2042void WebProcessPool::unregisterSchemeForCustomProtocol(const String& scheme)
2043{
2044#if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER)
2045 m_urlSchemesRegisteredForCustomProtocols.remove(scheme);
2046 sendToNetworkingProcess(Messages::LegacyCustomProtocolManager::UnregisterScheme(scheme));
2047#endif
2048}
2049
2050#if ENABLE(NETSCAPE_PLUGIN_API)
2051void WebProcessPool::setPluginLoadClientPolicy(WebCore::PluginLoadClientPolicy policy, const String& host, const String& bundleIdentifier, const String& versionString)
2052{
2053 auto& policiesForHost = m_pluginLoadClientPolicies.ensure(host, [] { return HashMap<String, HashMap<String, uint8_t>>(); }).iterator->value;
2054 auto& versionsToPolicies = policiesForHost.ensure(bundleIdentifier, [] { return HashMap<String, uint8_t>(); }).iterator->value;
2055 versionsToPolicies.set(versionString, policy);
2056
2057 sendToAllProcesses(Messages::WebProcess::SetPluginLoadClientPolicy(policy, host, bundleIdentifier, versionString));
2058}
2059
2060void WebProcessPool::resetPluginLoadClientPolicies(HashMap<String, HashMap<String, HashMap<String, uint8_t>>>&& pluginLoadClientPolicies)
2061{
2062 m_pluginLoadClientPolicies = WTFMove(pluginLoadClientPolicies);
2063 sendToAllProcesses(Messages::WebProcess::ResetPluginLoadClientPolicies(m_pluginLoadClientPolicies));
2064}
2065
2066void WebProcessPool::clearPluginClientPolicies()
2067{
2068 m_pluginLoadClientPolicies.clear();
2069 sendToAllProcesses(Messages::WebProcess::ClearPluginClientPolicies());
2070}
2071#endif
2072
2073void WebProcessPool::addSupportedPlugin(String&& matchingDomain, String&& name, HashSet<String>&& mimeTypes, HashSet<String> extensions)
2074{
2075#if ENABLE(NETSCAPE_PLUGIN_API)
2076 m_pluginInfoStore.addSupportedPlugin(WTFMove(matchingDomain), WTFMove(name), WTFMove(mimeTypes), WTFMove(extensions));
2077#else
2078 UNUSED_PARAM(matchingDomain);
2079 UNUSED_PARAM(name);
2080 UNUSED_PARAM(mimeTypes);
2081 UNUSED_PARAM(extensions);
2082#endif
2083}
2084
2085void WebProcessPool::clearSupportedPlugins()
2086{
2087#if ENABLE(NETSCAPE_PLUGIN_API)
2088 m_pluginInfoStore.clearSupportedPlugins();
2089#endif
2090}
2091
2092void WebProcessPool::setMemoryCacheDisabled(bool disabled)
2093{
2094 m_memoryCacheDisabled = disabled;
2095 sendToAllProcesses(Messages::WebProcess::SetMemoryCacheDisabled(disabled));
2096}
2097
2098void WebProcessPool::setFontWhitelist(API::Array* array)
2099{
2100 m_fontWhitelist.clear();
2101 if (array) {
2102 for (size_t i = 0; i < array->size(); ++i) {
2103 if (API::String* font = array->at<API::String>(i))
2104 m_fontWhitelist.append(font->string());
2105 }
2106 }
2107}
2108
2109void WebProcessPool::updateHiddenPageThrottlingAutoIncreaseLimit()
2110{
2111 // We're estimating an upper bound for a set of background timer fires for a page to be 200ms
2112 // (including all timer fires, all paging-in, and any resulting GC). To ensure this does not
2113 // result in more than 1% CPU load allow for one timer fire per 100x this duration.
2114 static int maximumTimerThrottlePerPageInMS = 200 * 100;
2115
2116 int limitInMilliseconds = maximumTimerThrottlePerPageInMS * m_hiddenPageThrottlingAutoIncreasesCounter.value();
2117 sendToAllProcesses(Messages::WebProcess::SetHiddenPageDOMTimerThrottlingIncreaseLimit(limitInMilliseconds));
2118}
2119
2120void WebProcessPool::reportWebContentCPUTime(Seconds cpuTime, uint64_t activityState)
2121{
2122#if PLATFORM(MAC)
2123 if (m_perActivityStateCPUUsageSampler)
2124 m_perActivityStateCPUUsageSampler->reportWebContentCPUTime(cpuTime, static_cast<WebCore::ActivityStateForCPUSampling>(activityState));
2125#else
2126 UNUSED_PARAM(cpuTime);
2127 UNUSED_PARAM(activityState);
2128#endif
2129}
2130
2131void WebProcessPool::updateProcessAssertions()
2132{
2133#if PLATFORM(IOS_FAMILY)
2134#if ENABLE(SERVICE_WORKER)
2135 auto updateServiceWorkerProcessAssertion = [&] {
2136 if (!m_serviceWorkerProcesses.isEmpty() && m_foregroundWebProcessCounter.value()) {
2137 // FIXME: We can do better than this once we have process per origin.
2138 for (auto* serviceWorkerProcess : m_serviceWorkerProcesses.values()) {
2139 auto& registrableDomain = serviceWorkerProcess->registrableDomain();
2140 if (!m_foregroundTokensForServiceWorkerProcesses.contains(registrableDomain))
2141 m_foregroundTokensForServiceWorkerProcesses.add(registrableDomain, serviceWorkerProcess->throttler().foregroundActivityToken());
2142 }
2143 m_backgroundTokensForServiceWorkerProcesses.clear();
2144 return;
2145 }
2146 if (!m_serviceWorkerProcesses.isEmpty() && m_backgroundWebProcessCounter.value()) {
2147 // FIXME: We can do better than this once we have process per origin.
2148 for (auto* serviceWorkerProcess : m_serviceWorkerProcesses.values()) {
2149 auto& registrableDomain = serviceWorkerProcess->registrableDomain();
2150 if (!m_backgroundTokensForServiceWorkerProcesses.contains(registrableDomain))
2151 m_backgroundTokensForServiceWorkerProcesses.add(registrableDomain, serviceWorkerProcess->throttler().backgroundActivityToken());
2152 }
2153 m_foregroundTokensForServiceWorkerProcesses.clear();
2154 return;
2155 }
2156 m_foregroundTokensForServiceWorkerProcesses.clear();
2157 m_backgroundTokensForServiceWorkerProcesses.clear();
2158 };
2159 updateServiceWorkerProcessAssertion();
2160#endif
2161
2162 auto updateNetworkProcessAssertion = [&] {
2163 auto& networkProcess = ensureNetworkProcess();
2164
2165 if (m_foregroundWebProcessCounter.value()) {
2166 if (!m_foregroundTokenForNetworkProcess) {
2167 m_foregroundTokenForNetworkProcess = networkProcess.throttler().foregroundActivityToken();
2168 networkProcess.sendProcessDidTransitionToForeground();
2169 }
2170 m_backgroundTokenForNetworkProcess = nullptr;
2171 return;
2172 }
2173 if (m_backgroundWebProcessCounter.value()) {
2174 if (!m_backgroundTokenForNetworkProcess) {
2175 m_backgroundTokenForNetworkProcess = networkProcess.throttler().backgroundActivityToken();
2176 networkProcess.sendProcessDidTransitionToBackground();
2177 }
2178 m_foregroundTokenForNetworkProcess = nullptr;
2179 return;
2180 }
2181 m_foregroundTokenForNetworkProcess = nullptr;
2182 m_backgroundTokenForNetworkProcess = nullptr;
2183 };
2184 updateNetworkProcessAssertion();
2185#endif
2186}
2187
2188#if ENABLE(SERVICE_WORKER)
2189void WebProcessPool::postMessageToServiceWorkerClient(const ServiceWorkerClientIdentifier& destination, MessageWithMessagePorts&& message, ServiceWorkerIdentifier source, const String& sourceOrigin)
2190{
2191 sendToNetworkingProcessRelaunchingIfNecessary(Messages::NetworkProcess::PostMessageToServiceWorkerClient(destination, WTFMove(message), source, sourceOrigin));
2192}
2193
2194void WebProcessPool::postMessageToServiceWorker(ServiceWorkerIdentifier destination, MessageWithMessagePorts&& message, const ServiceWorkerOrClientIdentifier& source, SWServerConnectionIdentifier connectionIdentifier)
2195{
2196 sendToNetworkingProcessRelaunchingIfNecessary(Messages::NetworkProcess::PostMessageToServiceWorker(destination, WTFMove(message), source, connectionIdentifier));
2197}
2198#endif
2199
2200void WebProcessPool::reinstateNetworkProcessAssertionState(NetworkProcessProxy& newNetworkProcessProxy)
2201{
2202#if PLATFORM(IOS_FAMILY)
2203 // The network process crashed; take new tokens for the new network process.
2204 if (m_backgroundTokenForNetworkProcess)
2205 m_backgroundTokenForNetworkProcess = newNetworkProcessProxy.throttler().backgroundActivityToken();
2206 else if (m_foregroundTokenForNetworkProcess)
2207 m_foregroundTokenForNetworkProcess = newNetworkProcessProxy.throttler().foregroundActivityToken();
2208#else
2209 UNUSED_PARAM(newNetworkProcessProxy);
2210#endif
2211}
2212
2213#if ENABLE(SERVICE_WORKER)
2214ServiceWorkerProcessProxy* WebProcessPool::serviceWorkerProcessProxyFromPageID(PageIdentifier pageID) const
2215{
2216 // FIXME: This is inefficient.
2217 for (auto* serviceWorkerProcess : m_serviceWorkerProcesses.values()) {
2218 if (serviceWorkerProcess->pageID() == pageID)
2219 return serviceWorkerProcess;
2220 }
2221 return nullptr;
2222}
2223#endif
2224
2225void WebProcessPool::addProcessToOriginCacheSet(WebProcessProxy& process, const URL& url)
2226{
2227 auto registrableDomain = WebCore::RegistrableDomain { url };
2228 auto result = m_swappedProcessesPerRegistrableDomain.add(registrableDomain, &process);
2229 if (!result.isNewEntry)
2230 result.iterator->value = &process;
2231
2232 LOG(ProcessSwapping, "(ProcessSwapping) Registrable domain %s just saved a cached process with pid %i", registrableDomain.string().utf8().data(), process.processIdentifier());
2233 if (!result.isNewEntry)
2234 LOG(ProcessSwapping, "(ProcessSwapping) Note: It already had one saved");
2235}
2236
2237void WebProcessPool::removeProcessFromOriginCacheSet(WebProcessProxy& process)
2238{
2239 LOG(ProcessSwapping, "(ProcessSwapping) Removing process with pid %i from the origin cache set", process.processIdentifier());
2240
2241 // FIXME: This can be very inefficient as the number of remembered origins and processes grows
2242 Vector<WebCore::RegistrableDomain> registrableDomainsToRemove;
2243 for (auto entry : m_swappedProcessesPerRegistrableDomain) {
2244 if (entry.value == &process)
2245 registrableDomainsToRemove.append(entry.key);
2246 }
2247
2248 for (auto& registrableDomain : registrableDomainsToRemove)
2249 m_swappedProcessesPerRegistrableDomain.remove(registrableDomain);
2250}
2251
2252void WebProcessPool::processForNavigation(WebPageProxy& page, const API::Navigation& navigation, Ref<WebProcessProxy>&& sourceProcess, const URL& sourceURL, ProcessSwapRequestedByClient processSwapRequestedByClient, Ref<WebsiteDataStore>&& dataStore, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&& completionHandler)
2253{
2254 processForNavigationInternal(page, navigation, sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, WTFMove(dataStore), [this, page = makeRefPtr(page), navigation = makeRef(navigation), sourceProcess = sourceProcess.copyRef(), sourceURL, processSwapRequestedByClient, completionHandler = WTFMove(completionHandler)](Ref<WebProcessProxy>&& process, SuspendedPageProxy* suspendedPage, const String& reason) mutable {
2255 // We are process-swapping so automatic process prewarming would be beneficial if the client has not explicitly enabled / disabled it.
2256 bool doingAnAutomaticProcessSwap = processSwapRequestedByClient == ProcessSwapRequestedByClient::No && process.ptr() != sourceProcess.ptr();
2257 if (doingAnAutomaticProcessSwap && !configuration().wasAutomaticProcessWarmingSetByClient() && !configuration().clientWouldBenefitFromAutomaticProcessPrewarming()) {
2258 RELEASE_LOG(PerformanceLogging, "Automatically turning on process prewarming because the client would benefit from it");
2259 configuration().setClientWouldBenefitFromAutomaticProcessPrewarming(true);
2260 }
2261
2262 if (m_configuration->alwaysKeepAndReuseSwappedProcesses() && process.ptr() != sourceProcess.ptr()) {
2263 static std::once_flag onceFlag;
2264 std::call_once(onceFlag, [] {
2265 WTFLogAlways("WARNING: The option to always keep swapped web processes alive is active. This is meant for debugging and testing only.");
2266 });
2267
2268 addProcessToOriginCacheSet(sourceProcess, sourceURL);
2269
2270 LOG(ProcessSwapping, "(ProcessSwapping) Navigating from %s to %s, keeping around old process. Now holding on to old processes for %u origins.", sourceURL.string().utf8().data(), navigation->currentRequest().url().string().utf8().data(), m_swappedProcessesPerRegistrableDomain.size());
2271 }
2272
2273 completionHandler(WTFMove(process), suspendedPage, reason);
2274 });
2275}
2276
2277void WebProcessPool::processForNavigationInternal(WebPageProxy& page, const API::Navigation& navigation, Ref<WebProcessProxy>&& sourceProcess, const URL& pageSourceURL, ProcessSwapRequestedByClient processSwapRequestedByClient, Ref<WebsiteDataStore>&& dataStore, CompletionHandler<void(Ref<WebProcessProxy>&&, SuspendedPageProxy*, const String&)>&& completionHandler)
2278{
2279 auto& targetURL = navigation.currentRequest().url();
2280 auto targetRegistrableDomain = WebCore::RegistrableDomain { targetURL };
2281
2282 auto createNewProcess = [this, protectedThis = makeRef(*this), page = makeRef(page), targetRegistrableDomain, dataStore = dataStore.copyRef()] () -> Ref<WebProcessProxy> {
2283 return processForRegistrableDomain(dataStore, page.ptr(), targetRegistrableDomain);
2284 };
2285
2286 if (usesSingleWebProcess())
2287 return completionHandler(WTFMove(sourceProcess), nullptr, "Single WebProcess mode is enabled"_s);
2288
2289 if (processSwapRequestedByClient == ProcessSwapRequestedByClient::Yes)
2290 return completionHandler(createNewProcess(), nullptr, "Process swap was requested by the client"_s);
2291
2292 if (!m_configuration->processSwapsOnNavigation())
2293 return completionHandler(WTFMove(sourceProcess), nullptr, "Feature is disabled"_s);
2294
2295 if (m_automationSession)
2296 return completionHandler(WTFMove(sourceProcess), nullptr, "An automation session is active"_s);
2297
2298 if (!sourceProcess->hasCommittedAnyProvisionalLoads()) {
2299 tryPrewarmWithDomainInformation(sourceProcess, targetRegistrableDomain);
2300 return completionHandler(WTFMove(sourceProcess), nullptr, "Process has not yet committed any provisional loads"_s);
2301 }
2302
2303 // FIXME: We should support process swap when a window has been opened via window.open() without 'noopener'.
2304 // The issue is that the opener has a handle to the WindowProxy.
2305 if (navigation.openedByDOMWithOpener() && !m_configuration->processSwapsOnWindowOpenWithOpener())
2306 return completionHandler(WTFMove(sourceProcess), nullptr, "Browsing context been opened by DOM without 'noopener'"_s);
2307
2308 // FIXME: We should support process swap when a window has opened other windows via window.open.
2309 if (navigation.hasOpenedFrames())
2310 return completionHandler(WTFMove(sourceProcess), nullptr, "Browsing context has opened other windows"_s);
2311
2312 if (auto* targetItem = navigation.targetItem()) {
2313 if (auto* suspendedPage = targetItem->suspendedPage()) {
2314 return suspendedPage->waitUntilReadyToUnsuspend([createNewProcess = WTFMove(createNewProcess), completionHandler = WTFMove(completionHandler)](SuspendedPageProxy* suspendedPage) mutable {
2315 if (!suspendedPage)
2316 return completionHandler(createNewProcess(), nullptr, "Using new process because target back/forward item's suspended page is not reusable"_s);
2317 Ref<WebProcessProxy> process = suspendedPage->process();
2318 completionHandler(WTFMove(process), suspendedPage, "Using target back/forward item's process and suspended page"_s);
2319 });
2320 }
2321
2322 if (RefPtr<WebProcessProxy> process = WebProcessProxy::processForIdentifier(targetItem->lastProcessIdentifier())) {
2323 if (process->state() != WebProcessProxy::State::Terminated) {
2324 // FIXME: Architecturally we do not currently support multiple WebPage's with the same ID in a given WebProcess.
2325 // In the case where this WebProcess has a SuspendedPageProxy for this WebPage, we can throw it away to support
2326 // WebProcess re-use.
2327 removeAllSuspendedPagesForPage(page, process.get());
2328
2329 // Make sure we remove the process from the cache if it is in there since we're about to use it.
2330 if (process->isInProcessCache()) {
2331 webProcessCache().removeProcess(*process, WebProcessCache::ShouldShutDownProcess::No);
2332 ASSERT(!process->isInProcessCache());
2333 }
2334
2335 return completionHandler(process.releaseNonNull(), nullptr, "Using target back/forward item's process"_s);
2336 }
2337 }
2338 }
2339
2340 if (navigation.treatAsSameOriginNavigation())
2341 return completionHandler(WTFMove(sourceProcess), nullptr, "The treatAsSameOriginNavigation flag is set"_s);
2342
2343 URL sourceURL;
2344 if (page.isPageOpenedByDOMShowingInitialEmptyDocument() && !navigation.requesterOrigin().isEmpty())
2345 sourceURL = URL { URL(), navigation.requesterOrigin().toString() };
2346 else
2347 sourceURL = pageSourceURL;
2348
2349 if (sourceURL.isEmpty() && page.configuration().relatedPage()) {
2350 sourceURL = URL { { }, page.configuration().relatedPage()->pageLoadState().url() };
2351 RELEASE_LOG(ProcessSwapping, "Using related page %p's URL as source URL for process swap decision", page.configuration().relatedPage());
2352 }
2353
2354 if (!sourceURL.isValid() || !targetURL.isValid() || sourceURL.isEmpty() || sourceURL.protocolIsAbout() || targetRegistrableDomain.matches(sourceURL))
2355 return completionHandler(WTFMove(sourceProcess), nullptr, "Navigation is same-site"_s);
2356
2357 String reason = "Navigation is cross-site"_s;
2358
2359 if (m_configuration->alwaysKeepAndReuseSwappedProcesses()) {
2360 LOG(ProcessSwapping, "(ProcessSwapping) Considering re-use of a previously cached process for domain %s", targetRegistrableDomain.string().utf8().data());
2361
2362 if (auto* process = m_swappedProcessesPerRegistrableDomain.get(targetRegistrableDomain)) {
2363 if (&process->websiteDataStore() == dataStore.ptr()) {
2364 LOG(ProcessSwapping, "(ProcessSwapping) Reusing a previously cached process with pid %i to continue navigation to URL %s", process->processIdentifier(), targetURL.string().utf8().data());
2365
2366 // FIXME: Architecturally we do not currently support multiple WebPage's with the same ID in a given WebProcess.
2367 // In the case where this WebProcess has a SuspendedPageProxy for this WebPage, we can throw it away to support
2368 // WebProcess re-use.
2369 // In the future it would be great to refactor-out this limitation (https://bugs.webkit.org/show_bug.cgi?id=191166).
2370 removeAllSuspendedPagesForPage(page, process);
2371
2372 return completionHandler(makeRef(*process), nullptr, reason);
2373 }
2374 }
2375 }
2376
2377 return completionHandler(createNewProcess(), nullptr, reason);
2378}
2379
2380RefPtr<WebProcessProxy> WebProcessPool::findReusableSuspendedPageProcess(const WebCore::RegistrableDomain& registrableDomain, WebPageProxy& page, WebsiteDataStore& dataStore)
2381{
2382 auto it = m_suspendedPages.findIf([&](auto& suspendedPage) {
2383 return suspendedPage->process().registrableDomain() == registrableDomain && &suspendedPage->process().websiteDataStore() == &dataStore;
2384 });
2385 if (it == m_suspendedPages.end())
2386 return nullptr;
2387
2388 Ref<WebProcessProxy> process = (*it)->process();
2389
2390 // FIXME: If the SuspendedPage is for this page, then we need to destroy the suspended page as we do not support having
2391 // multiple WebPages with the same ID in a given WebProcess currently (https://bugs.webkit.org/show_bug.cgi?id=191166).
2392 if (&(*it)->page() == &page)
2393 m_suspendedPages.remove(it);
2394
2395
2396 return process;
2397}
2398
2399void WebProcessPool::addSuspendedPage(std::unique_ptr<SuspendedPageProxy>&& suspendedPage)
2400{
2401 if (!m_maxSuspendedPageCount)
2402 return;
2403
2404 if (m_suspendedPages.size() >= m_maxSuspendedPageCount)
2405 m_suspendedPages.removeFirst();
2406
2407 m_suspendedPages.append(WTFMove(suspendedPage));
2408}
2409
2410void WebProcessPool::removeAllSuspendedPagesForPage(WebPageProxy& page, WebProcessProxy* process)
2411{
2412 m_suspendedPages.removeAllMatching([&page, process](auto& suspendedPage) {
2413 return &suspendedPage->page() == &page && (!process || &suspendedPage->process() == process);
2414 });
2415}
2416
2417std::unique_ptr<SuspendedPageProxy> WebProcessPool::takeSuspendedPage(SuspendedPageProxy& suspendedPage)
2418{
2419 return m_suspendedPages.takeFirst([&suspendedPage](auto& item) {
2420 return item.get() == &suspendedPage;
2421 });
2422}
2423
2424void WebProcessPool::removeSuspendedPage(SuspendedPageProxy& suspendedPage)
2425{
2426 auto it = m_suspendedPages.findIf([&suspendedPage](auto& item) {
2427 return item.get() == &suspendedPage;
2428 });
2429 if (it != m_suspendedPages.end())
2430 m_suspendedPages.remove(it);
2431}
2432
2433bool WebProcessPool::hasSuspendedPageFor(WebProcessProxy& process, WebPageProxy& page) const
2434{
2435 return m_suspendedPages.findIf([&process, &page](auto& suspendedPage) {
2436 return &suspendedPage->process() == &process && &suspendedPage->page() == &page;
2437 }) != m_suspendedPages.end();
2438}
2439
2440void WebProcessPool::clearSuspendedPages(AllowProcessCaching allowProcessCaching)
2441{
2442 HashSet<RefPtr<WebProcessProxy>> processes;
2443 for (auto& suspendedPage : m_suspendedPages)
2444 processes.add(&suspendedPage->process());
2445
2446 m_suspendedPages.clear();
2447
2448 for (auto& process : processes)
2449 process->maybeShutDown(allowProcessCaching);
2450}
2451
2452void WebProcessPool::addMockMediaDevice(const MockMediaDevice& device)
2453{
2454#if ENABLE(MEDIA_STREAM)
2455 MockRealtimeMediaSourceCenter::addDevice(device);
2456 sendToAllProcesses(Messages::WebProcess::AddMockMediaDevice { device });
2457#endif
2458}
2459
2460void WebProcessPool::clearMockMediaDevices()
2461{
2462#if ENABLE(MEDIA_STREAM)
2463 MockRealtimeMediaSourceCenter::setDevices({ });
2464 sendToAllProcesses(Messages::WebProcess::ClearMockMediaDevices { });
2465#endif
2466}
2467
2468void WebProcessPool::removeMockMediaDevice(const String& persistentId)
2469{
2470#if ENABLE(MEDIA_STREAM)
2471 MockRealtimeMediaSourceCenter::removeDevice(persistentId);
2472 sendToAllProcesses(Messages::WebProcess::RemoveMockMediaDevice { persistentId });
2473#endif
2474}
2475
2476void WebProcessPool::resetMockMediaDevices()
2477{
2478#if ENABLE(MEDIA_STREAM)
2479 MockRealtimeMediaSourceCenter::resetDevices();
2480 sendToAllProcesses(Messages::WebProcess::ResetMockMediaDevices { });
2481#endif
2482}
2483
2484void WebProcessPool::sendDisplayConfigurationChangedMessageForTesting()
2485{
2486#if PLATFORM(MAC) && ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
2487 auto display = CGSMainDisplayID();
2488
2489 for (auto& processPool : WebProcessPool::allProcessPools()) {
2490 processPool->sendToAllProcesses(Messages::WebProcess::DisplayConfigurationChanged(display, kCGDisplayBeginConfigurationFlag));
2491 processPool->sendToAllProcesses(Messages::WebProcess::DisplayConfigurationChanged(display, kCGDisplaySetModeFlag | kCGDisplayDesktopShapeChangedFlag));
2492 }
2493#endif
2494}
2495
2496void WebProcessPool::didCollectPrewarmInformation(const WebCore::RegistrableDomain& registrableDomain, const WebCore::PrewarmInformation& prewarmInformation)
2497{
2498 static const size_t maximumSizeToPreventUnlimitedGrowth = 100;
2499 if (m_prewarmInformationPerRegistrableDomain.size() == maximumSizeToPreventUnlimitedGrowth)
2500 m_prewarmInformationPerRegistrableDomain.remove(m_prewarmInformationPerRegistrableDomain.random());
2501
2502 auto& value = m_prewarmInformationPerRegistrableDomain.ensure(registrableDomain, [] {
2503 return std::make_unique<WebCore::PrewarmInformation>();
2504 }).iterator->value;
2505
2506 *value = prewarmInformation;
2507}
2508
2509void WebProcessPool::tryPrewarmWithDomainInformation(WebProcessProxy& process, const RegistrableDomain& registrableDomain)
2510{
2511 auto* prewarmInformation = m_prewarmInformationPerRegistrableDomain.get(registrableDomain);
2512 if (!prewarmInformation)
2513 return;
2514 process.send(Messages::WebProcess::PrewarmWithDomainInformation(*prewarmInformation), 0);
2515}
2516
2517void WebProcessPool::clearCurrentModifierStateForTesting()
2518{
2519 sendToAllProcesses(Messages::WebProcess::ClearCurrentModifierStateForTesting());
2520}
2521
2522#if ENABLE(RESOURCE_LOAD_STATISTICS)
2523void WebProcessPool::didCommitCrossSiteLoadWithDataTransfer(PAL::SessionID sessionID, const RegistrableDomain& fromDomain, const RegistrableDomain& toDomain, OptionSet<CrossSiteNavigationDataTransfer::Flag> navigationDataTransfer, PageIdentifier pageID)
2524{
2525 if (!m_networkProcess)
2526 return;
2527
2528 m_networkProcess->didCommitCrossSiteLoadWithDataTransfer(sessionID, fromDomain, toDomain, navigationDataTransfer, pageID);
2529}
2530#endif
2531
2532void WebProcessPool::setWebProcessHasUploads(ProcessIdentifier processID)
2533{
2534 ASSERT(processID);
2535 auto* process = WebProcessProxy::processForIdentifier(processID);
2536 ASSERT(process);
2537
2538 if (!process)
2539 return;
2540
2541 RELEASE_LOG(ProcessSuspension, "Web process pid %u now has uploads in progress", (unsigned)process->processIdentifier());
2542
2543 if (m_processesWithUploads.isEmpty()) {
2544 RELEASE_LOG(ProcessSuspension, "The number of uploads in progress is now one. Taking Networking and UI process assertions.");
2545
2546 ASSERT(m_networkProcess);
2547 m_networkProcess->takeUploadAssertion();
2548
2549 ASSERT(!m_uiProcessUploadAssertion);
2550 m_uiProcessUploadAssertion = std::make_unique<ProcessAssertion>(getCurrentProcessID(), "WebKit uploads"_s, AssertionState::UnboundedNetworking);
2551 }
2552
2553 auto result = m_processesWithUploads.add(processID, nullptr);
2554 ASSERT(result.isNewEntry);
2555 result.iterator->value = std::make_unique<ProcessAssertion>(process->processIdentifier(), "WebKit uploads"_s, AssertionState::UnboundedNetworking);
2556}
2557
2558void WebProcessPool::clearWebProcessHasUploads(ProcessIdentifier processID)
2559{
2560 ASSERT(processID);
2561 auto result = m_processesWithUploads.take(processID);
2562 if (!result)
2563 return;
2564
2565 auto* process = WebProcessProxy::processForIdentifier(processID);
2566 ASSERT_UNUSED(process, process);
2567 RELEASE_LOG(ProcessSuspension, "Web process pid %u no longer has uploads in progress", (unsigned)process->processIdentifier());
2568
2569 if (m_processesWithUploads.isEmpty()) {
2570 RELEASE_LOG(ProcessSuspension, "The number of uploads in progress is now zero. Releasing Networking and UI process assertions.");
2571
2572 if (m_networkProcess)
2573 m_networkProcess->clearUploadAssertion();
2574
2575 ASSERT(m_uiProcessUploadAssertion);
2576 m_uiProcessUploadAssertion = nullptr;
2577 }
2578
2579}
2580
2581void WebProcessPool::setWebProcessIsPlayingAudibleMedia(WebCore::ProcessIdentifier processID)
2582{
2583 auto* process = WebProcessProxy::processForIdentifier(processID);
2584 ASSERT(process);
2585
2586 RELEASE_LOG(ProcessSuspension, "Web process pid %u is now playing audible media", (unsigned)process->processIdentifier());
2587
2588 if (m_processesPlayingAudibleMedia.isEmpty()) {
2589 RELEASE_LOG(ProcessSuspension, "The number of processes playing audible media is now one. Taking UI process assertion.");
2590
2591 ASSERT(!m_uiProcessMediaPlaybackAssertion);
2592 m_uiProcessMediaPlaybackAssertion = std::make_unique<ProcessAssertion>(getCurrentProcessID(), "WebKit Media Playback"_s, AssertionState::Foreground, AssertionReason::MediaPlayback);
2593 }
2594
2595 auto result = m_processesPlayingAudibleMedia.add(processID, nullptr);
2596 ASSERT(result.isNewEntry);
2597 result.iterator->value = std::make_unique<ProcessAssertion>(process->processIdentifier(), "WebKit Media Playback"_s, AssertionState::Foreground, AssertionReason::MediaPlayback);
2598}
2599
2600void WebProcessPool::clearWebProcessIsPlayingAudibleMedia(WebCore::ProcessIdentifier processID)
2601{
2602 auto result = m_processesPlayingAudibleMedia.take(processID);
2603 ASSERT_UNUSED(result, result);
2604
2605 auto* process = WebProcessProxy::processForIdentifier(processID);
2606 ASSERT_UNUSED(process, process);
2607
2608 RELEASE_LOG(ProcessSuspension, "Web process pid %u is no longer playing audible media", (unsigned)process->processIdentifier());
2609
2610 if (m_processesPlayingAudibleMedia.isEmpty()) {
2611 RELEASE_LOG(ProcessSuspension, "The number of processes playing audible media now zero. Releasing UI process assertion.");
2612
2613 ASSERT(m_uiProcessMediaPlaybackAssertion);
2614 m_uiProcessMediaPlaybackAssertion = nullptr;
2615 }
2616}
2617
2618} // namespace WebKit
2619