1/*
2 * Copyright (C) 2009-2019 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 "WebProcess.h"
28
29#include "APIFrameHandle.h"
30#include "APIPageGroupHandle.h"
31#include "APIPageHandle.h"
32#include "AuthenticationManager.h"
33#include "AuxiliaryProcessMessages.h"
34#include "DrawingArea.h"
35#include "EventDispatcher.h"
36#include "InjectedBundle.h"
37#include "LibWebRTCNetwork.h"
38#include "Logging.h"
39#include "NetworkConnectionToWebProcessMessages.h"
40#include "NetworkProcessConnection.h"
41#include "NetworkSession.h"
42#include "NetworkSessionCreationParameters.h"
43#include "PluginProcessConnectionManager.h"
44#include "StatisticsData.h"
45#include "UserData.h"
46#include "WebAutomationSessionProxy.h"
47#include "WebCacheStorageProvider.h"
48#include "WebConnectionToUIProcess.h"
49#include "WebCoreArgumentCoders.h"
50#include "WebFrame.h"
51#include "WebFrameNetworkingContext.h"
52#include "WebGamepadProvider.h"
53#include "WebGeolocationManager.h"
54#include "WebLoaderStrategy.h"
55#include "WebMediaKeyStorageManager.h"
56#include "WebMemorySampler.h"
57#include "WebMessagePortChannelProvider.h"
58#include "WebPage.h"
59#include "WebPageGroupProxy.h"
60#include "WebPaymentCoordinator.h"
61#include "WebPlatformStrategies.h"
62#include "WebPluginInfoProvider.h"
63#include "WebProcessCreationParameters.h"
64#include "WebProcessDataStoreParameters.h"
65#include "WebProcessMessages.h"
66#include "WebProcessPoolMessages.h"
67#include "WebProcessProxyMessages.h"
68#include "WebSWContextManagerConnection.h"
69#include "WebSWContextManagerConnectionMessages.h"
70#include "WebServiceWorkerProvider.h"
71#include "WebSocketStream.h"
72#include "WebsiteData.h"
73#include "WebsiteDataStoreParameters.h"
74#include "WebsiteDataType.h"
75#include <JavaScriptCore/JSLock.h>
76#include <JavaScriptCore/MemoryStatistics.h>
77#include <JavaScriptCore/WasmFaultSignalHandler.h>
78#include <WebCore/AXObjectCache.h>
79#include <WebCore/ApplicationCacheStorage.h>
80#include <WebCore/AuthenticationChallenge.h>
81#include <WebCore/CPUMonitor.h>
82#include <WebCore/CommonVM.h>
83#include <WebCore/CrossOriginPreflightResultCache.h>
84#include <WebCore/DNS.h>
85#include <WebCore/DOMWindow.h>
86#include <WebCore/DatabaseManager.h>
87#include <WebCore/DatabaseTracker.h>
88#include <WebCore/DeprecatedGlobalSettings.h>
89#include <WebCore/DiagnosticLoggingClient.h>
90#include <WebCore/DiagnosticLoggingKeys.h>
91#include <WebCore/FontCache.h>
92#include <WebCore/FontCascade.h>
93#include <WebCore/Frame.h>
94#include <WebCore/FrameLoader.h>
95#include <WebCore/GCController.h>
96#include <WebCore/GlyphPage.h>
97#include <WebCore/HTMLMediaElement.h>
98#include <WebCore/JSDOMWindow.h>
99#include <WebCore/MemoryCache.h>
100#include <WebCore/MemoryRelease.h>
101#include <WebCore/MessagePort.h>
102#include <WebCore/MockRealtimeMediaSourceCenter.h>
103#include <WebCore/NetworkStorageSession.h>
104#include <WebCore/Page.h>
105#include <WebCore/PageCache.h>
106#include <WebCore/PageGroup.h>
107#include <WebCore/PlatformKeyboardEvent.h>
108#include <WebCore/PlatformMediaSessionManager.h>
109#include <WebCore/ProcessWarming.h>
110#include <WebCore/RegistrableDomain.h>
111#include <WebCore/ResourceLoadObserver.h>
112#include <WebCore/ResourceLoadStatistics.h>
113#include <WebCore/RuntimeApplicationChecks.h>
114#include <WebCore/RuntimeEnabledFeatures.h>
115#include <WebCore/SchemeRegistry.h>
116#include <WebCore/SecurityOrigin.h>
117#include <WebCore/ServiceWorkerContextData.h>
118#include <WebCore/Settings.h>
119#include <WebCore/UserGestureIndicator.h>
120#include <wtf/Algorithms.h>
121#include <wtf/Language.h>
122#include <wtf/ProcessPrivilege.h>
123#include <wtf/RunLoop.h>
124#include <wtf/SystemTracing.h>
125#include <wtf/URLParser.h>
126#include <wtf/text/StringHash.h>
127
128#if !OS(WINDOWS)
129#include <unistd.h>
130#endif
131
132#if PLATFORM(WAYLAND)
133#include "WaylandCompositorDisplay.h"
134#endif
135
136#if PLATFORM(COCOA)
137#include "ObjCObjectGraph.h"
138#include "UserMediaCaptureManager.h"
139#endif
140
141#if PLATFORM(IOS_FAMILY)
142#include "WebSQLiteDatabaseTracker.h"
143#endif
144
145#if ENABLE(SEC_ITEM_SHIM)
146#include "SecItemShim.h"
147#endif
148
149#if ENABLE(NOTIFICATIONS)
150#include "WebNotificationManager.h"
151#endif
152
153#if ENABLE(REMOTE_INSPECTOR)
154#include <JavaScriptCore/RemoteInspector.h>
155#endif
156
157// This should be less than plugInAutoStartExpirationTimeThreshold in PlugInAutoStartProvider.
158static const Seconds plugInAutoStartExpirationTimeUpdateThreshold { 29 * 24 * 60 * 60 };
159
160// This should be greater than tileRevalidationTimeout in TileController.
161static const Seconds nonVisibleProcessCleanupDelay { 10_s };
162
163namespace WebKit {
164using namespace JSC;
165using namespace WebCore;
166
167NO_RETURN static void callExit(IPC::Connection*)
168{
169 _exit(EXIT_SUCCESS);
170}
171
172WebProcess& WebProcess::singleton()
173{
174 static WebProcess& process = *new WebProcess;
175 return process;
176}
177
178WebProcess::WebProcess()
179 : m_eventDispatcher(EventDispatcher::create())
180#if PLATFORM(IOS_FAMILY)
181 , m_viewUpdateDispatcher(ViewUpdateDispatcher::create())
182#endif
183 , m_webInspectorInterruptDispatcher(WebInspectorInterruptDispatcher::create())
184 , m_webLoaderStrategy(*new WebLoaderStrategy)
185 , m_cacheStorageProvider(WebCacheStorageProvider::create())
186 , m_dnsPrefetchHystereris([this](PAL::HysteresisState state) { if (state == PAL::HysteresisState::Stopped) m_dnsPrefetchedHosts.clear(); })
187#if ENABLE(NETSCAPE_PLUGIN_API)
188 , m_pluginProcessConnectionManager(PluginProcessConnectionManager::create())
189#endif
190 , m_nonVisibleProcessCleanupTimer(*this, &WebProcess::nonVisibleProcessCleanupTimerFired)
191#if PLATFORM(IOS_FAMILY)
192 , m_webSQLiteDatabaseTracker([this](bool isHoldingLockedFiles) { parentProcessConnection()->send(Messages::WebProcessProxy::SetIsHoldingLockedFiles(isHoldingLockedFiles), 0); })
193#endif
194{
195 // Initialize our platform strategies.
196 WebPlatformStrategies::initialize();
197
198 // FIXME: This should moved to where WebProcess::initialize is called,
199 // so that ports have a chance to customize, and ifdefs in this file are
200 // limited.
201 addSupplement<WebGeolocationManager>();
202
203#if ENABLE(NOTIFICATIONS)
204 addSupplement<WebNotificationManager>();
205#endif
206
207#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
208 addSupplement<WebMediaKeyStorageManager>();
209#endif
210
211#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
212 addSupplement<UserMediaCaptureManager>();
213#endif
214
215 m_plugInAutoStartOriginHashes.add(PAL::SessionID::defaultSessionID(), HashMap<unsigned, WallTime>());
216
217#if ENABLE(RESOURCE_LOAD_STATISTICS)
218 ResourceLoadObserver::shared().setStatisticsUpdatedCallback([this] (Vector<ResourceLoadStatistics>&& statistics) {
219 ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::ResourceLoadStatisticsUpdated(WTFMove(statistics)), 0);
220 });
221
222 ResourceLoadObserver::shared().setRequestStorageAccessUnderOpenerCallback([this] (PAL::SessionID sessionID, const RegistrableDomain& domainInNeedOfStorageAccess, uint64_t openerPageID, const RegistrableDomain& openerDomain) {
223 ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::RequestStorageAccessUnderOpener(sessionID, domainInNeedOfStorageAccess, openerPageID, openerDomain), 0);
224 });
225#endif
226
227 Gigacage::disableDisablingPrimitiveGigacageIfShouldBeEnabled();
228}
229
230WebProcess::~WebProcess()
231{
232}
233
234void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameters& parameters)
235{
236 WTF::setProcessPrivileges({ });
237
238 MessagePortChannelProvider::setSharedProvider(WebMessagePortChannelProvider::singleton());
239
240 platformInitializeProcess(parameters);
241 updateCPULimit();
242}
243
244void WebProcess::initializeConnection(IPC::Connection* connection)
245{
246 AuxiliaryProcess::initializeConnection(connection);
247
248 // We call _exit() directly from the background queue in case the main thread is unresponsive
249 // and AuxiliaryProcess::didClose() does not get called.
250 connection->setDidCloseOnConnectionWorkQueueCallback(callExit);
251
252#if !PLATFORM(GTK) && !PLATFORM(WPE)
253 connection->setShouldExitOnSyncMessageSendFailure(true);
254#endif
255
256#if HAVE(QOS_CLASSES)
257 connection->setShouldBoostMainThreadOnSyncMessage(true);
258#endif
259
260 m_eventDispatcher->initializeConnection(connection);
261#if PLATFORM(IOS_FAMILY)
262 m_viewUpdateDispatcher->initializeConnection(connection);
263#endif // PLATFORM(IOS_FAMILY)
264 m_webInspectorInterruptDispatcher->initializeConnection(connection);
265
266#if ENABLE(NETSCAPE_PLUGIN_API)
267 m_pluginProcessConnectionManager->initializeConnection(connection);
268#endif
269
270 for (auto& supplement : m_supplements.values())
271 supplement->initializeConnection(connection);
272
273 m_webConnection = WebConnectionToUIProcess::create(this);
274}
275
276void WebProcess::initializeWebProcess(WebProcessCreationParameters&& parameters)
277{
278 TraceScope traceScope(InitializeWebProcessStart, InitializeWebProcessEnd);
279
280 ASSERT(m_pageMap.isEmpty());
281
282 WebCore::setPresentingApplicationPID(parameters.presentingApplicationPID);
283
284#if OS(LINUX)
285 MemoryPressureHandler::ReliefLogger::setLoggingEnabled(parameters.shouldEnableMemoryPressureReliefLogging);
286#endif
287
288 platformInitializeWebProcess(parameters);
289
290 // Match the QoS of the UIProcess and the scrolling thread but use a slightly lower priority.
291 WTF::Thread::setCurrentThreadIsUserInteractive(-1);
292
293 m_suppressMemoryPressureHandler = parameters.shouldSuppressMemoryPressureHandler;
294 if (!m_suppressMemoryPressureHandler) {
295 auto& memoryPressureHandler = MemoryPressureHandler::singleton();
296 memoryPressureHandler.setLowMemoryHandler([this] (Critical critical, Synchronous synchronous) {
297#if PLATFORM(MAC)
298 // If this is a process we keep around for performance, kill it on memory pressure instead of trying to free up its memory.
299 if (m_processType == ProcessType::CachedWebContent || m_processType == ProcessType::PrewarmedWebContent || areAllPagesSuspended()) {
300 if (m_processType == ProcessType::CachedWebContent)
301 RELEASE_LOG(Process, "Cached WebProcess %i is exiting due to memory pressure", getpid());
302 else if (m_processType == ProcessType::PrewarmedWebContent)
303 RELEASE_LOG(Process, "Prewarmed WebProcess %i is exiting due to memory pressure", getpid());
304 else
305 RELEASE_LOG(Process, "Suspended WebProcess %i is exiting due to memory pressure", getpid());
306 stopRunLoop();
307 return;
308 }
309#endif
310
311 auto maintainPageCache = m_isSuspending && hasPageRequiringPageCacheWhileSuspended() ? WebCore::MaintainPageCache::Yes : WebCore::MaintainPageCache::No;
312 auto maintainMemoryCache = m_isSuspending && m_hasSuspendedPageProxy ? WebCore::MaintainMemoryCache::Yes : WebCore::MaintainMemoryCache::No;
313 WebCore::releaseMemory(critical, synchronous, maintainPageCache, maintainMemoryCache);
314 });
315#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101200) || PLATFORM(GTK) || PLATFORM(WPE)
316 memoryPressureHandler.setShouldUsePeriodicMemoryMonitor(true);
317 memoryPressureHandler.setMemoryKillCallback([this] () {
318 WebCore::logMemoryStatisticsAtTimeOfDeath();
319 if (MemoryPressureHandler::singleton().processState() == WebsamProcessState::Active)
320 parentProcessConnection()->send(Messages::WebProcessProxy::DidExceedActiveMemoryLimit(), 0);
321 else
322 parentProcessConnection()->send(Messages::WebProcessProxy::DidExceedInactiveMemoryLimit(), 0);
323 });
324 memoryPressureHandler.setDidExceedInactiveLimitWhileActiveCallback([this] () {
325 parentProcessConnection()->send(Messages::WebProcessProxy::DidExceedInactiveMemoryLimitWhileActive(), 0);
326 });
327#endif
328 memoryPressureHandler.setMemoryPressureStatusChangedCallback([this](bool isUnderMemoryPressure) {
329 if (parentProcessConnection())
330 parentProcessConnection()->send(Messages::WebProcessProxy::MemoryPressureStatusChanged(isUnderMemoryPressure), 0);
331 });
332 memoryPressureHandler.install();
333 }
334
335 for (size_t i = 0, size = parameters.additionalSandboxExtensionHandles.size(); i < size; ++i)
336 SandboxExtension::consumePermanently(parameters.additionalSandboxExtensionHandles[i]);
337
338 if (!parameters.injectedBundlePath.isEmpty())
339 m_injectedBundle = InjectedBundle::create(parameters, transformHandlesToObjects(parameters.initializationUserData.object()).get());
340
341 for (auto& supplement : m_supplements.values())
342 supplement->initialize(parameters);
343
344 setCacheModel(parameters.cacheModel);
345
346 if (!parameters.languages.isEmpty())
347 overrideUserPreferredLanguages(parameters.languages);
348
349 m_textCheckerState = parameters.textCheckerState;
350
351 m_fullKeyboardAccessEnabled = parameters.fullKeyboardAccessEnabled;
352
353 for (auto& scheme : parameters.urlSchemesRegisteredAsEmptyDocument)
354 registerURLSchemeAsEmptyDocument(scheme);
355
356 for (auto& scheme : parameters.urlSchemesRegisteredAsSecure)
357 registerURLSchemeAsSecure(scheme);
358
359 for (auto& scheme : parameters.urlSchemesRegisteredAsBypassingContentSecurityPolicy)
360 registerURLSchemeAsBypassingContentSecurityPolicy(scheme);
361
362 for (auto& scheme : parameters.urlSchemesForWhichDomainRelaxationIsForbidden)
363 setDomainRelaxationForbiddenForURLScheme(scheme);
364
365 for (auto& scheme : parameters.urlSchemesRegisteredAsLocal)
366 registerURLSchemeAsLocal(scheme);
367
368 for (auto& scheme : parameters.urlSchemesRegisteredAsNoAccess)
369 registerURLSchemeAsNoAccess(scheme);
370
371 for (auto& scheme : parameters.urlSchemesRegisteredAsDisplayIsolated)
372 registerURLSchemeAsDisplayIsolated(scheme);
373
374 for (auto& scheme : parameters.urlSchemesRegisteredAsCORSEnabled)
375 registerURLSchemeAsCORSEnabled(scheme);
376
377 for (auto& scheme : parameters.urlSchemesRegisteredAsAlwaysRevalidated)
378 registerURLSchemeAsAlwaysRevalidated(scheme);
379
380 for (auto& scheme : parameters.urlSchemesRegisteredAsCachePartitioned)
381 registerURLSchemeAsCachePartitioned(scheme);
382
383 for (auto& scheme : parameters.urlSchemesServiceWorkersCanHandle)
384 registerURLSchemeServiceWorkersCanHandle(scheme);
385
386 for (auto& scheme : parameters.urlSchemesRegisteredAsCanDisplayOnlyIfCanRequest)
387 registerURLSchemeAsCanDisplayOnlyIfCanRequest(scheme);
388
389 setDefaultRequestTimeoutInterval(parameters.defaultRequestTimeoutInterval);
390
391 setAlwaysUsesComplexTextCodePath(parameters.shouldAlwaysUseComplexTextCodePath);
392
393 setShouldUseFontSmoothing(parameters.shouldUseFontSmoothing);
394
395 ensureNetworkProcessConnection();
396
397#if ENABLE(RESOURCE_LOAD_STATISTICS)
398 ResourceLoadObserver::shared().setLogUserInteractionNotificationCallback([this] (PAL::SessionID sessionID, const RegistrableDomain& domain) {
399 ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::LogUserInteraction(sessionID, domain), 0);
400 });
401
402 ResourceLoadObserver::shared().setLogWebSocketLoadingNotificationCallback([this] (PAL::SessionID sessionID, const RegistrableDomain& targetDomain, const RegistrableDomain& topFrameDomain, WallTime lastSeen) {
403 ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::LogWebSocketLoading(sessionID, targetDomain, topFrameDomain, lastSeen), 0);
404 });
405
406 ResourceLoadObserver::shared().setLogSubresourceLoadingNotificationCallback([this] (PAL::SessionID sessionID, const RegistrableDomain& targetDomain, const RegistrableDomain& topFrameDomain, WallTime lastSeen) {
407 ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::LogSubresourceLoading(sessionID, targetDomain, topFrameDomain, lastSeen), 0);
408 });
409
410 ResourceLoadObserver::shared().setLogSubresourceRedirectNotificationCallback([this] (PAL::SessionID sessionID, const RegistrableDomain& sourceDomain, const RegistrableDomain& targetDomain) {
411 ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::LogSubresourceRedirect(sessionID, sourceDomain, targetDomain), 0);
412 });
413#endif
414
415 setTerminationTimeout(parameters.terminationTimeout);
416
417 resetPlugInAutoStartOriginHashes(parameters.plugInAutoStartOriginHashes);
418 for (auto& origin : parameters.plugInAutoStartOrigins)
419 m_plugInAutoStartOrigins.add(origin);
420
421 setMemoryCacheDisabled(parameters.memoryCacheDisabled);
422
423 WebCore::RuntimeEnabledFeatures::sharedFeatures().setAttrStyleEnabled(parameters.attrStyleEnabled);
424
425#if ENABLE(SERVICE_CONTROLS)
426 setEnabledServices(parameters.hasImageServices, parameters.hasSelectionServices, parameters.hasRichContentServices);
427#endif
428
429#if ENABLE(REMOTE_INSPECTOR) && PLATFORM(COCOA)
430 if (Optional<audit_token_t> auditToken = parentProcessConnection()->getAuditToken()) {
431 RetainPtr<CFDataRef> auditData = adoptCF(CFDataCreate(nullptr, (const UInt8*)&*auditToken, sizeof(*auditToken)));
432 Inspector::RemoteInspector::singleton().setParentProcessInformation(WebCore::presentingApplicationPID(), auditData);
433 }
434#endif
435
436#if ENABLE(NETSCAPE_PLUGIN_API) && PLATFORM(MAC)
437 resetPluginLoadClientPolicies(parameters.pluginLoadClientPolicies);
438#endif
439
440#if ENABLE(GAMEPAD)
441 GamepadProvider::singleton().setSharedProvider(WebGamepadProvider::singleton());
442#endif
443
444#if ENABLE(SERVICE_WORKER)
445 ServiceWorkerProvider::setSharedProvider(WebServiceWorkerProvider::singleton());
446#endif
447
448#if ENABLE(WEBASSEMBLY)
449 JSC::Wasm::enableFastMemory();
450#endif
451
452#if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
453 ResourceLoadObserver::shared().setShouldLogUserInteraction(parameters.shouldLogUserInteraction);
454#endif
455
456 RELEASE_LOG(Process, "%p - WebProcess::initializeWebProcess: Presenting process = %d", this, WebCore::presentingApplicationPID());
457}
458
459void WebProcess::setWebsiteDataStoreParameters(WebProcessDataStoreParameters&& parameters)
460{
461 auto& databaseManager = DatabaseManager::singleton();
462 databaseManager.initialize(parameters.webSQLDatabaseDirectory);
463
464 // FIXME: This should be constructed per data store, not per process.
465 m_applicationCacheStorage = ApplicationCacheStorage::create(parameters.applicationCacheDirectory, parameters.applicationCacheFlatFileSubdirectoryName);
466#if PLATFORM(IOS_FAMILY)
467 m_applicationCacheStorage->setDefaultOriginQuota(25ULL * 1024 * 1024);
468#endif
469
470#if ENABLE(VIDEO)
471 if (!parameters.mediaCacheDirectory.isEmpty())
472 WebCore::HTMLMediaElement::setMediaCacheDirectory(parameters.mediaCacheDirectory);
473#endif
474
475 setResourceLoadStatisticsEnabled(parameters.resourceLoadStatisticsEnabled);
476
477 for (auto& supplement : m_supplements.values())
478 supplement->setWebsiteDataStore(parameters);
479
480 platformSetWebsiteDataStoreParameters(WTFMove(parameters));
481}
482
483bool WebProcess::hasPageRequiringPageCacheWhileSuspended() const
484{
485 for (auto& page : m_pageMap.values()) {
486 if (page->isSuspended())
487 return true;
488 }
489 return false;
490}
491
492bool WebProcess::areAllPagesSuspended() const
493{
494 for (auto& page : m_pageMap.values()) {
495 if (!page->isSuspended())
496 return false;
497 }
498 return true;
499}
500
501void WebProcess::setHasSuspendedPageProxy(bool hasSuspendedPageProxy)
502{
503 ASSERT(m_hasSuspendedPageProxy != hasSuspendedPageProxy);
504 m_hasSuspendedPageProxy = hasSuspendedPageProxy;
505}
506
507void WebProcess::setIsInProcessCache(bool isInProcessCache)
508{
509#if PLATFORM(COCOA)
510 if (isInProcessCache) {
511 ASSERT(m_processType == ProcessType::WebContent);
512 m_processType = ProcessType::CachedWebContent;
513 } else {
514 ASSERT(m_processType == ProcessType::CachedWebContent);
515 m_processType = ProcessType::WebContent;
516 }
517
518 updateProcessName();
519#else
520 UNUSED_PARAM(isInProcessCache);
521#endif
522}
523
524void WebProcess::markIsNoLongerPrewarmed()
525{
526#if PLATFORM(COCOA)
527 ASSERT(m_processType == ProcessType::PrewarmedWebContent);
528 m_processType = ProcessType::WebContent;
529
530 updateProcessName();
531#endif
532}
533
534void WebProcess::prewarmGlobally()
535{
536 WebCore::ProcessWarming::prewarmGlobally();
537}
538
539void WebProcess::prewarmWithDomainInformation(const WebCore::PrewarmInformation& prewarmInformation)
540{
541 WebCore::ProcessWarming::prewarmWithInformation(prewarmInformation);
542}
543
544void WebProcess::registerURLSchemeAsEmptyDocument(const String& urlScheme)
545{
546 SchemeRegistry::registerURLSchemeAsEmptyDocument(urlScheme);
547}
548
549void WebProcess::registerURLSchemeAsSecure(const String& urlScheme) const
550{
551 SchemeRegistry::registerURLSchemeAsSecure(urlScheme);
552}
553
554void WebProcess::registerURLSchemeAsBypassingContentSecurityPolicy(const String& urlScheme) const
555{
556 SchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(urlScheme);
557}
558
559void WebProcess::setDomainRelaxationForbiddenForURLScheme(const String& urlScheme) const
560{
561 SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(true, urlScheme);
562}
563
564void WebProcess::registerURLSchemeAsLocal(const String& urlScheme) const
565{
566 SchemeRegistry::registerURLSchemeAsLocal(urlScheme);
567}
568
569void WebProcess::registerURLSchemeAsNoAccess(const String& urlScheme) const
570{
571 SchemeRegistry::registerURLSchemeAsNoAccess(urlScheme);
572}
573
574void WebProcess::registerURLSchemeAsDisplayIsolated(const String& urlScheme) const
575{
576 SchemeRegistry::registerURLSchemeAsDisplayIsolated(urlScheme);
577}
578
579void WebProcess::registerURLSchemeAsCORSEnabled(const String& urlScheme) const
580{
581 SchemeRegistry::registerURLSchemeAsCORSEnabled(urlScheme);
582}
583
584void WebProcess::registerURLSchemeAsAlwaysRevalidated(const String& urlScheme) const
585{
586 SchemeRegistry::registerURLSchemeAsAlwaysRevalidated(urlScheme);
587}
588
589void WebProcess::registerURLSchemeAsCachePartitioned(const String& urlScheme) const
590{
591 SchemeRegistry::registerURLSchemeAsCachePartitioned(urlScheme);
592}
593
594void WebProcess::registerURLSchemeAsCanDisplayOnlyIfCanRequest(const String& urlScheme) const
595{
596 SchemeRegistry::registerAsCanDisplayOnlyIfCanRequest(urlScheme);
597}
598
599void WebProcess::setDefaultRequestTimeoutInterval(double timeoutInterval)
600{
601 ResourceRequest::setDefaultTimeoutInterval(timeoutInterval);
602}
603
604void WebProcess::setAlwaysUsesComplexTextCodePath(bool alwaysUseComplexText)
605{
606 WebCore::FontCascade::setCodePath(alwaysUseComplexText ? WebCore::FontCascade::Complex : WebCore::FontCascade::Auto);
607}
608
609void WebProcess::setShouldUseFontSmoothing(bool useFontSmoothing)
610{
611 WebCore::FontCascade::setShouldUseSmoothing(useFontSmoothing);
612}
613
614void WebProcess::userPreferredLanguagesChanged(const Vector<String>& languages) const
615{
616 overrideUserPreferredLanguages(languages);
617}
618
619void WebProcess::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled)
620{
621 m_fullKeyboardAccessEnabled = fullKeyboardAccessEnabled;
622}
623
624void WebProcess::ensureLegacyPrivateBrowsingSessionInNetworkProcess()
625{
626 ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::EnsureLegacyPrivateBrowsingSession(), 0);
627}
628
629#if ENABLE(NETSCAPE_PLUGIN_API)
630PluginProcessConnectionManager& WebProcess::pluginProcessConnectionManager()
631{
632 return *m_pluginProcessConnectionManager;
633}
634#endif
635
636void WebProcess::setCacheModel(CacheModel cacheModel)
637{
638 if (m_hasSetCacheModel && (cacheModel == m_cacheModel))
639 return;
640
641 m_hasSetCacheModel = true;
642 m_cacheModel = cacheModel;
643
644 unsigned cacheTotalCapacity = 0;
645 unsigned cacheMinDeadCapacity = 0;
646 unsigned cacheMaxDeadCapacity = 0;
647 Seconds deadDecodedDataDeletionInterval;
648 unsigned pageCacheSize = 0;
649 calculateMemoryCacheSizes(cacheModel, cacheTotalCapacity, cacheMinDeadCapacity, cacheMaxDeadCapacity, deadDecodedDataDeletionInterval, pageCacheSize);
650
651 auto& memoryCache = MemoryCache::singleton();
652 memoryCache.setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity);
653 memoryCache.setDeadDecodedDataDeletionInterval(deadDecodedDataDeletionInterval);
654 PageCache::singleton().setMaxSize(pageCacheSize);
655
656 platformSetCacheModel(cacheModel);
657}
658
659WebPage* WebProcess::focusedWebPage() const
660{
661 for (auto& page : m_pageMap.values()) {
662 if (page->windowAndWebPageAreFocused())
663 return page.get();
664 }
665 return 0;
666}
667
668WebPage* WebProcess::webPage(uint64_t pageID) const
669{
670 return m_pageMap.get(pageID);
671}
672
673void WebProcess::createWebPage(uint64_t pageID, WebPageCreationParameters&& parameters)
674{
675 // It is necessary to check for page existence here since during a window.open() (or targeted
676 // link) the WebPage gets created both in the synchronous handler and through the normal way.
677 HashMap<uint64_t, RefPtr<WebPage>>::AddResult result = m_pageMap.add(pageID, nullptr);
678 if (result.isNewEntry) {
679 ASSERT(!result.iterator->value);
680 result.iterator->value = WebPage::create(pageID, WTFMove(parameters));
681
682 // Balanced by an enableTermination in removeWebPage.
683 disableTermination();
684 updateCPULimit();
685 } else
686 result.iterator->value->reinitializeWebPage(WTFMove(parameters));
687
688 ASSERT(result.iterator->value);
689}
690
691void WebProcess::removeWebPage(uint64_t pageID)
692{
693 ASSERT(m_pageMap.contains(pageID));
694
695 pageWillLeaveWindow(pageID);
696 m_pageMap.remove(pageID);
697
698 enableTermination();
699 updateCPULimit();
700}
701
702bool WebProcess::shouldTerminate()
703{
704 ASSERT(m_pageMap.isEmpty());
705
706 // FIXME: the ShouldTerminate message should also send termination parameters, such as any session cookies that need to be preserved.
707 bool shouldTerminate = false;
708 if (parentProcessConnection()->sendSync(Messages::WebProcessProxy::ShouldTerminate(), Messages::WebProcessProxy::ShouldTerminate::Reply(shouldTerminate), 0)
709 && !shouldTerminate)
710 return false;
711
712 return true;
713}
714
715void WebProcess::terminate()
716{
717#ifndef NDEBUG
718 GCController::singleton().garbageCollectNow();
719 FontCache::singleton().invalidate();
720 MemoryCache::singleton().setDisabled(true);
721#endif
722
723 m_webConnection->invalidate();
724 m_webConnection = nullptr;
725
726 platformTerminate();
727
728 AuxiliaryProcess::terminate();
729}
730
731void WebProcess::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& replyEncoder)
732{
733 if (messageReceiverMap().dispatchSyncMessage(connection, decoder, replyEncoder))
734 return;
735}
736
737void WebProcess::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
738{
739 if (messageReceiverMap().dispatchMessage(connection, decoder))
740 return;
741
742 if (decoder.messageReceiverName() == Messages::WebProcess::messageReceiverName()) {
743 didReceiveWebProcessMessage(connection, decoder);
744 return;
745 }
746
747 if (decoder.messageReceiverName() == Messages::AuxiliaryProcess::messageReceiverName()) {
748 AuxiliaryProcess::didReceiveMessage(connection, decoder);
749 return;
750 }
751
752#if ENABLE(SERVICE_WORKER)
753 // FIXME: Remove?
754 if (decoder.messageReceiverName() == Messages::WebSWContextManagerConnection::messageReceiverName()) {
755 ASSERT(SWContextManager::singleton().connection());
756 if (auto* contextManagerConnection = SWContextManager::singleton().connection())
757 static_cast<WebSWContextManagerConnection&>(*contextManagerConnection).didReceiveMessage(connection, decoder);
758 return;
759 }
760#endif
761
762 LOG_ERROR("Unhandled web process message '%s:%s'", decoder.messageReceiverName().toString().data(), decoder.messageName().toString().data());
763}
764
765WebFrame* WebProcess::webFrame(uint64_t frameID) const
766{
767 return m_frameMap.get(frameID);
768}
769
770void WebProcess::addWebFrame(uint64_t frameID, WebFrame* frame)
771{
772 m_frameMap.set(frameID, frame);
773}
774
775void WebProcess::removeWebFrame(uint64_t frameID)
776{
777 m_frameMap.remove(frameID);
778
779 // We can end up here after our connection has closed when WebCore's frame life-support timer
780 // fires when the application is shutting down. There's no need (and no way) to update the UI
781 // process in this case.
782 if (!parentProcessConnection())
783 return;
784
785 parentProcessConnection()->send(Messages::WebProcessProxy::DidDestroyFrame(frameID), 0);
786}
787
788WebPageGroupProxy* WebProcess::webPageGroup(PageGroup* pageGroup)
789{
790 for (auto& page : m_pageGroupMap.values()) {
791 if (page->corePageGroup() == pageGroup)
792 return page.get();
793 }
794
795 return 0;
796}
797
798WebPageGroupProxy* WebProcess::webPageGroup(uint64_t pageGroupID)
799{
800 return m_pageGroupMap.get(pageGroupID);
801}
802
803WebPageGroupProxy* WebProcess::webPageGroup(const WebPageGroupData& pageGroupData)
804{
805 auto result = m_pageGroupMap.add(pageGroupData.pageGroupID, nullptr);
806 if (result.isNewEntry) {
807 ASSERT(!result.iterator->value);
808 result.iterator->value = WebPageGroupProxy::create(pageGroupData);
809 }
810
811 return result.iterator->value.get();
812}
813
814static uint64_t nextUserGestureTokenIdentifier()
815{
816 static uint64_t identifier = 1;
817 return identifier++;
818}
819
820uint64_t WebProcess::userGestureTokenIdentifier(RefPtr<UserGestureToken> token)
821{
822 if (!token || !token->processingUserGesture())
823 return 0;
824
825 auto result = m_userGestureTokens.ensure(token.get(), [] { return nextUserGestureTokenIdentifier(); });
826 if (result.isNewEntry) {
827 result.iterator->key->addDestructionObserver([] (UserGestureToken& tokenBeingDestroyed) {
828 WebProcess::singleton().userGestureTokenDestroyed(tokenBeingDestroyed);
829 });
830 }
831
832 return result.iterator->value;
833}
834
835void WebProcess::userGestureTokenDestroyed(UserGestureToken& token)
836{
837 auto identifier = m_userGestureTokens.take(&token);
838 parentProcessConnection()->send(Messages::WebProcessProxy::DidDestroyUserGestureToken(identifier), 0);
839}
840
841void WebProcess::clearResourceCaches(ResourceCachesToClear resourceCachesToClear)
842{
843 // Toggling the cache model like this forces the cache to evict all its in-memory resources.
844 // FIXME: We need a better way to do this.
845 CacheModel cacheModel = m_cacheModel;
846 setCacheModel(CacheModel::DocumentViewer);
847 setCacheModel(cacheModel);
848
849 MemoryCache::singleton().evictResources();
850
851 // Empty the cross-origin preflight cache.
852 CrossOriginPreflightResultCache::singleton().clear();
853}
854
855static inline void addCaseFoldedCharacters(StringHasher& hasher, const String& string)
856{
857 if (string.isEmpty())
858 return;
859 if (string.is8Bit()) {
860 hasher.addCharacters<LChar, ASCIICaseInsensitiveHash::FoldCase<LChar>>(string.characters8(), string.length());
861 return;
862 }
863 hasher.addCharacters<UChar, ASCIICaseInsensitiveHash::FoldCase<UChar>>(string.characters16(), string.length());
864}
865
866static unsigned hashForPlugInOrigin(const String& pageOrigin, const String& pluginOrigin, const String& mimeType)
867{
868 // We want to avoid concatenating the strings and then taking the hash, since that could lead to an expensive conversion.
869 // We also want to avoid using the hash() function in StringImpl or ASCIICaseInsensitiveHash because that masks out bits for the use of flags.
870 StringHasher hasher;
871 addCaseFoldedCharacters(hasher, pageOrigin);
872 hasher.addCharacter(0);
873 addCaseFoldedCharacters(hasher, pluginOrigin);
874 hasher.addCharacter(0);
875 addCaseFoldedCharacters(hasher, mimeType);
876 return hasher.hash();
877}
878
879bool WebProcess::isPlugInAutoStartOriginHash(unsigned plugInOriginHash, PAL::SessionID sessionID)
880{
881 HashMap<PAL::SessionID, HashMap<unsigned, WallTime>>::const_iterator sessionIterator = m_plugInAutoStartOriginHashes.find(sessionID);
882 HashMap<unsigned, WallTime>::const_iterator it;
883 bool contains = false;
884
885 if (sessionIterator != m_plugInAutoStartOriginHashes.end()) {
886 it = sessionIterator->value.find(plugInOriginHash);
887 contains = it != sessionIterator->value.end();
888 }
889 if (!contains) {
890 sessionIterator = m_plugInAutoStartOriginHashes.find(PAL::SessionID::defaultSessionID());
891 it = sessionIterator->value.find(plugInOriginHash);
892 if (it == sessionIterator->value.end())
893 return false;
894 }
895 return WallTime::now() < it->value;
896}
897
898bool WebProcess::shouldPlugInAutoStartFromOrigin(WebPage& webPage, const String& pageOrigin, const String& pluginOrigin, const String& mimeType)
899{
900 if (!pluginOrigin.isEmpty() && m_plugInAutoStartOrigins.contains(pluginOrigin))
901 return true;
902
903#ifdef ENABLE_PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC
904 // The plugin wasn't in the general whitelist, so check if it similar to the primary plugin for the page (if we've found one).
905 if (webPage.matchesPrimaryPlugIn(pageOrigin, pluginOrigin, mimeType))
906 return true;
907#else
908 UNUSED_PARAM(webPage);
909#endif
910
911 // Lastly check against the more explicit hash list.
912 return isPlugInAutoStartOriginHash(hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType), webPage.sessionID());
913}
914
915void WebProcess::plugInDidStartFromOrigin(const String& pageOrigin, const String& pluginOrigin, const String& mimeType, PAL::SessionID sessionID)
916{
917 if (pageOrigin.isEmpty()) {
918 LOG(Plugins, "Not adding empty page origin");
919 return;
920 }
921
922 unsigned plugInOriginHash = hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType);
923 if (isPlugInAutoStartOriginHash(plugInOriginHash, sessionID)) {
924 LOG(Plugins, "Hash %x already exists as auto-start origin (request for %s)", plugInOriginHash, pageOrigin.utf8().data());
925 return;
926 }
927
928 // We might attempt to start another plugin before the didAddPlugInAutoStartOrigin message
929 // comes back from the parent process. Temporarily add this hash to the list with a thirty
930 // second timeout. That way, even if the parent decides not to add it, we'll only be
931 // incorrect for a little while.
932 m_plugInAutoStartOriginHashes.add(sessionID, HashMap<unsigned, WallTime>()).iterator->value.set(plugInOriginHash, WallTime::now() + 30_s * 1000);
933
934 parentProcessConnection()->send(Messages::WebProcessPool::AddPlugInAutoStartOriginHash(pageOrigin, plugInOriginHash, sessionID), 0);
935}
936
937void WebProcess::didAddPlugInAutoStartOriginHash(unsigned plugInOriginHash, WallTime expirationTime, PAL::SessionID sessionID)
938{
939 // When called, some web process (which also might be this one) added the origin for auto-starting,
940 // or received user interaction.
941 // Set the bit to avoid having redundantly call into the UI process upon user interaction.
942 m_plugInAutoStartOriginHashes.add(sessionID, HashMap<unsigned, WallTime>()).iterator->value.set(plugInOriginHash, expirationTime);
943}
944
945void WebProcess::resetPlugInAutoStartOriginDefaultHashes(const HashMap<unsigned, WallTime>& hashes)
946{
947 m_plugInAutoStartOriginHashes.clear();
948 m_plugInAutoStartOriginHashes.add(PAL::SessionID::defaultSessionID(), HashMap<unsigned, WallTime>()).iterator->value.swap(const_cast<HashMap<unsigned, WallTime>&>(hashes));
949}
950
951void WebProcess::resetPlugInAutoStartOriginHashes(const HashMap<PAL::SessionID, HashMap<unsigned, WallTime>>& hashes)
952{
953 m_plugInAutoStartOriginHashes.swap(const_cast<HashMap<PAL::SessionID, HashMap<unsigned, WallTime>>&>(hashes));
954}
955
956void WebProcess::plugInDidReceiveUserInteraction(const String& pageOrigin, const String& pluginOrigin, const String& mimeType, PAL::SessionID sessionID)
957{
958 if (pageOrigin.isEmpty())
959 return;
960
961 unsigned plugInOriginHash = hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType);
962 if (!plugInOriginHash)
963 return;
964
965 HashMap<PAL::SessionID, HashMap<unsigned, WallTime>>::const_iterator sessionIterator = m_plugInAutoStartOriginHashes.find(sessionID);
966 HashMap<unsigned, WallTime>::const_iterator it;
967 bool contains = false;
968 if (sessionIterator != m_plugInAutoStartOriginHashes.end()) {
969 it = sessionIterator->value.find(plugInOriginHash);
970 contains = it != sessionIterator->value.end();
971 }
972 if (!contains) {
973 sessionIterator = m_plugInAutoStartOriginHashes.find(PAL::SessionID::defaultSessionID());
974 it = sessionIterator->value.find(plugInOriginHash);
975 if (it == sessionIterator->value.end())
976 return;
977 }
978
979 if (it->value - WallTime::now() > plugInAutoStartExpirationTimeUpdateThreshold)
980 return;
981
982 parentProcessConnection()->send(Messages::WebProcessPool::PlugInDidReceiveUserInteraction(plugInOriginHash, sessionID), 0);
983}
984
985void WebProcess::setPluginLoadClientPolicy(uint8_t policy, const String& host, const String& bundleIdentifier, const String& versionString)
986{
987#if ENABLE(NETSCAPE_PLUGIN_API) && PLATFORM(MAC)
988 WebPluginInfoProvider::singleton().setPluginLoadClientPolicy(static_cast<PluginLoadClientPolicy>(policy), host, bundleIdentifier, versionString);
989#endif
990}
991
992void WebProcess::resetPluginLoadClientPolicies(const HashMap<WTF::String, HashMap<WTF::String, HashMap<WTF::String, uint8_t>>>& pluginLoadClientPolicies)
993{
994#if ENABLE(NETSCAPE_PLUGIN_API) && PLATFORM(MAC)
995 clearPluginClientPolicies();
996
997 for (auto& hostPair : pluginLoadClientPolicies) {
998 for (auto& bundleIdentifierPair : hostPair.value) {
999 for (auto& versionPair : bundleIdentifierPair.value)
1000 WebPluginInfoProvider::singleton().setPluginLoadClientPolicy(static_cast<PluginLoadClientPolicy>(versionPair.value), hostPair.key, bundleIdentifierPair.key, versionPair.key);
1001 }
1002 }
1003#endif
1004}
1005
1006void WebProcess::isJITEnabled(CompletionHandler<void(bool)>&& completionHandler)
1007{
1008 completionHandler(JSC::VM::canUseJIT());
1009}
1010
1011void WebProcess::clearPluginClientPolicies()
1012{
1013#if ENABLE(NETSCAPE_PLUGIN_API) && PLATFORM(MAC)
1014 WebPluginInfoProvider::singleton().clearPluginClientPolicies();
1015#endif
1016}
1017
1018void WebProcess::refreshPlugins()
1019{
1020#if ENABLE(NETSCAPE_PLUGIN_API)
1021 WebPluginInfoProvider::singleton().refresh(false);
1022#endif
1023}
1024
1025static void fromCountedSetToHashMap(TypeCountSet* countedSet, HashMap<String, uint64_t>& map)
1026{
1027 TypeCountSet::const_iterator end = countedSet->end();
1028 for (TypeCountSet::const_iterator it = countedSet->begin(); it != end; ++it)
1029 map.set(it->key, it->value);
1030}
1031
1032static void getWebCoreMemoryCacheStatistics(Vector<HashMap<String, uint64_t>>& result)
1033{
1034 String imagesString("Images"_s);
1035 String cssString("CSS"_s);
1036 String xslString("XSL"_s);
1037 String javaScriptString("JavaScript"_s);
1038
1039 MemoryCache::Statistics memoryCacheStatistics = MemoryCache::singleton().getStatistics();
1040
1041 HashMap<String, uint64_t> counts;
1042 counts.set(imagesString, memoryCacheStatistics.images.count);
1043 counts.set(cssString, memoryCacheStatistics.cssStyleSheets.count);
1044 counts.set(xslString, memoryCacheStatistics.xslStyleSheets.count);
1045 counts.set(javaScriptString, memoryCacheStatistics.scripts.count);
1046 result.append(counts);
1047
1048 HashMap<String, uint64_t> sizes;
1049 sizes.set(imagesString, memoryCacheStatistics.images.size);
1050 sizes.set(cssString, memoryCacheStatistics.cssStyleSheets.size);
1051 sizes.set(xslString, memoryCacheStatistics.xslStyleSheets.size);
1052 sizes.set(javaScriptString, memoryCacheStatistics.scripts.size);
1053 result.append(sizes);
1054
1055 HashMap<String, uint64_t> liveSizes;
1056 liveSizes.set(imagesString, memoryCacheStatistics.images.liveSize);
1057 liveSizes.set(cssString, memoryCacheStatistics.cssStyleSheets.liveSize);
1058 liveSizes.set(xslString, memoryCacheStatistics.xslStyleSheets.liveSize);
1059 liveSizes.set(javaScriptString, memoryCacheStatistics.scripts.liveSize);
1060 result.append(liveSizes);
1061
1062 HashMap<String, uint64_t> decodedSizes;
1063 decodedSizes.set(imagesString, memoryCacheStatistics.images.decodedSize);
1064 decodedSizes.set(cssString, memoryCacheStatistics.cssStyleSheets.decodedSize);
1065 decodedSizes.set(xslString, memoryCacheStatistics.xslStyleSheets.decodedSize);
1066 decodedSizes.set(javaScriptString, memoryCacheStatistics.scripts.decodedSize);
1067 result.append(decodedSizes);
1068}
1069
1070void WebProcess::getWebCoreStatistics(uint64_t callbackID)
1071{
1072 StatisticsData data;
1073
1074 // Gather JavaScript statistics.
1075 {
1076 JSLockHolder lock(commonVM());
1077 data.statisticsNumbers.set("JavaScriptObjectsCount"_s, commonVM().heap.objectCount());
1078 data.statisticsNumbers.set("JavaScriptGlobalObjectsCount"_s, commonVM().heap.globalObjectCount());
1079 data.statisticsNumbers.set("JavaScriptProtectedObjectsCount"_s, commonVM().heap.protectedObjectCount());
1080 data.statisticsNumbers.set("JavaScriptProtectedGlobalObjectsCount"_s, commonVM().heap.protectedGlobalObjectCount());
1081
1082 std::unique_ptr<TypeCountSet> protectedObjectTypeCounts(commonVM().heap.protectedObjectTypeCounts());
1083 fromCountedSetToHashMap(protectedObjectTypeCounts.get(), data.javaScriptProtectedObjectTypeCounts);
1084
1085 std::unique_ptr<TypeCountSet> objectTypeCounts(commonVM().heap.objectTypeCounts());
1086 fromCountedSetToHashMap(objectTypeCounts.get(), data.javaScriptObjectTypeCounts);
1087
1088 uint64_t javaScriptHeapSize = commonVM().heap.size();
1089 data.statisticsNumbers.set("JavaScriptHeapSize"_s, javaScriptHeapSize);
1090 data.statisticsNumbers.set("JavaScriptFreeSize"_s, commonVM().heap.capacity() - javaScriptHeapSize);
1091 }
1092
1093 WTF::FastMallocStatistics fastMallocStatistics = WTF::fastMallocStatistics();
1094 data.statisticsNumbers.set("FastMallocReservedVMBytes"_s, fastMallocStatistics.reservedVMBytes);
1095 data.statisticsNumbers.set("FastMallocCommittedVMBytes"_s, fastMallocStatistics.committedVMBytes);
1096 data.statisticsNumbers.set("FastMallocFreeListBytes"_s, fastMallocStatistics.freeListBytes);
1097
1098 // Gather font statistics.
1099 auto& fontCache = FontCache::singleton();
1100 data.statisticsNumbers.set("CachedFontDataCount"_s, fontCache.fontCount());
1101 data.statisticsNumbers.set("CachedFontDataInactiveCount"_s, fontCache.inactiveFontCount());
1102
1103 // Gather glyph page statistics.
1104 data.statisticsNumbers.set("GlyphPageCount"_s, GlyphPage::count());
1105
1106 // Get WebCore memory cache statistics
1107 getWebCoreMemoryCacheStatistics(data.webCoreCacheStatistics);
1108
1109 parentProcessConnection()->send(Messages::WebProcessPool::DidGetStatistics(data, callbackID), 0);
1110}
1111
1112void WebProcess::garbageCollectJavaScriptObjects()
1113{
1114 GCController::singleton().garbageCollectNow();
1115}
1116
1117void WebProcess::mainThreadPing()
1118{
1119 parentProcessConnection()->send(Messages::WebProcessProxy::DidReceiveMainThreadPing(), 0);
1120}
1121
1122void WebProcess::backgroundResponsivenessPing()
1123{
1124 parentProcessConnection()->send(Messages::WebProcessProxy::DidReceiveBackgroundResponsivenessPing(), 0);
1125}
1126
1127void WebProcess::didTakeAllMessagesForPort(Vector<MessageWithMessagePorts>&& messages, uint64_t messageCallbackIdentifier, uint64_t messageBatchIdentifier)
1128{
1129 WebMessagePortChannelProvider::singleton().didTakeAllMessagesForPort(WTFMove(messages), messageCallbackIdentifier, messageBatchIdentifier);
1130}
1131
1132void WebProcess::checkProcessLocalPortForActivity(const MessagePortIdentifier& port, uint64_t callbackIdentifier)
1133{
1134 WebMessagePortChannelProvider::singleton().checkProcessLocalPortForActivity(port, callbackIdentifier);
1135}
1136
1137void WebProcess::didCheckRemotePortForActivity(uint64_t callbackIdentifier, bool hasActivity)
1138{
1139 WebMessagePortChannelProvider::singleton().didCheckRemotePortForActivity(callbackIdentifier, hasActivity);
1140}
1141
1142void WebProcess::messagesAvailableForPort(const MessagePortIdentifier& identifier)
1143{
1144 MessagePort::notifyMessageAvailable(identifier);
1145}
1146
1147#if ENABLE(GAMEPAD)
1148
1149void WebProcess::setInitialGamepads(const Vector<WebKit::GamepadData>& gamepadDatas)
1150{
1151 WebGamepadProvider::singleton().setInitialGamepads(gamepadDatas);
1152}
1153
1154void WebProcess::gamepadConnected(const GamepadData& gamepadData)
1155{
1156 WebGamepadProvider::singleton().gamepadConnected(gamepadData);
1157}
1158
1159void WebProcess::gamepadDisconnected(unsigned index)
1160{
1161 WebGamepadProvider::singleton().gamepadDisconnected(index);
1162}
1163
1164#endif
1165
1166void WebProcess::setJavaScriptGarbageCollectorTimerEnabled(bool flag)
1167{
1168 GCController::singleton().setJavaScriptGarbageCollectorTimerEnabled(flag);
1169}
1170
1171void WebProcess::handleInjectedBundleMessage(const String& messageName, const UserData& messageBody)
1172{
1173 InjectedBundle* injectedBundle = WebProcess::singleton().injectedBundle();
1174 if (!injectedBundle)
1175 return;
1176
1177 injectedBundle->didReceiveMessage(messageName, transformHandlesToObjects(messageBody.object()).get());
1178}
1179
1180void WebProcess::setInjectedBundleParameter(const String& key, const IPC::DataReference& value)
1181{
1182 InjectedBundle* injectedBundle = WebProcess::singleton().injectedBundle();
1183 if (!injectedBundle)
1184 return;
1185
1186 injectedBundle->setBundleParameter(key, value);
1187}
1188
1189void WebProcess::setInjectedBundleParameters(const IPC::DataReference& value)
1190{
1191 InjectedBundle* injectedBundle = WebProcess::singleton().injectedBundle();
1192 if (!injectedBundle)
1193 return;
1194
1195 injectedBundle->setBundleParameters(value);
1196}
1197
1198static IPC::Connection::Identifier getNetworkProcessConnection(IPC::Connection& connection)
1199{
1200 IPC::Attachment encodedConnectionIdentifier;
1201 if (!connection.sendSync(Messages::WebProcessProxy::GetNetworkProcessConnection(), Messages::WebProcessProxy::GetNetworkProcessConnection::Reply(encodedConnectionIdentifier), 0)) {
1202#if PLATFORM(GTK) || PLATFORM(WPE)
1203 // GTK+ and WPE ports don't exit on send sync message failure.
1204 // In this particular case, the network process can be terminated by the UI process while the
1205 // Web process is still initializing, so we always want to exit instead of crashing. This can
1206 // happen when the WebView is created and then destroyed quickly.
1207 // See https://bugs.webkit.org/show_bug.cgi?id=183348.
1208 exit(0);
1209#else
1210 CRASH();
1211#endif
1212 }
1213
1214#if USE(UNIX_DOMAIN_SOCKETS)
1215 return encodedConnectionIdentifier.releaseFileDescriptor();
1216#elif OS(DARWIN)
1217 return encodedConnectionIdentifier.port();
1218#elif OS(WINDOWS)
1219 return encodedConnectionIdentifier.handle();
1220#else
1221 ASSERT_NOT_REACHED();
1222 return IPC::Connection::Identifier();
1223#endif
1224}
1225
1226NetworkProcessConnection& WebProcess::ensureNetworkProcessConnection()
1227{
1228 RELEASE_ASSERT(RunLoop::isMain());
1229
1230 // If we've lost our connection to the network process (e.g. it crashed) try to re-establish it.
1231 if (!m_networkProcessConnection) {
1232 IPC::Connection::Identifier connectionIdentifier = getNetworkProcessConnection(*parentProcessConnection());
1233
1234 // Retry once if the IPC to get the connectionIdentifier succeeded but the connectionIdentifier we received
1235 // is invalid. This may indicate that the network process has crashed.
1236 if (!IPC::Connection::identifierIsValid(connectionIdentifier))
1237 connectionIdentifier = getNetworkProcessConnection(*parentProcessConnection());
1238
1239 if (!IPC::Connection::identifierIsValid(connectionIdentifier))
1240 CRASH();
1241
1242 m_networkProcessConnection = NetworkProcessConnection::create(connectionIdentifier);
1243 m_networkProcessConnection->connection().send(Messages::NetworkConnectionToWebProcess::SetWebProcessIdentifier(Process::identifier()), 0);
1244 }
1245
1246 return *m_networkProcessConnection;
1247}
1248
1249void WebProcess::logDiagnosticMessageForNetworkProcessCrash()
1250{
1251 WebCore::Page* page = nullptr;
1252
1253 if (auto* webPage = focusedWebPage())
1254 page = webPage->corePage();
1255
1256 if (!page) {
1257 for (auto& webPage : m_pageMap.values()) {
1258 if (auto* corePage = webPage->corePage()) {
1259 page = corePage;
1260 break;
1261 }
1262 }
1263 }
1264
1265 if (page)
1266 page->diagnosticLoggingClient().logDiagnosticMessage(WebCore::DiagnosticLoggingKeys::internalErrorKey(), WebCore::DiagnosticLoggingKeys::networkProcessCrashedKey(), WebCore::ShouldSample::No);
1267}
1268
1269void WebProcess::networkProcessConnectionClosed(NetworkProcessConnection* connection)
1270{
1271 ASSERT(m_networkProcessConnection);
1272 ASSERT_UNUSED(connection, m_networkProcessConnection == connection);
1273
1274#if ENABLE(INDEXED_DATABASE)
1275 for (auto& page : m_pageMap.values()) {
1276 auto idbConnection = page->corePage()->optionalIDBConnection();
1277 if (!idbConnection)
1278 continue;
1279
1280 if (connection->existingIDBConnectionToServerForIdentifier(idbConnection->identifier())) {
1281 ASSERT(idbConnection == &connection->existingIDBConnectionToServerForIdentifier(idbConnection->identifier())->coreConnectionToServer());
1282 page->corePage()->clearIDBConnection();
1283 }
1284 }
1285#endif
1286
1287#if ENABLE(SERVICE_WORKER)
1288 if (SWContextManager::singleton().connection()) {
1289 RELEASE_LOG(ServiceWorker, "Service worker process is exiting because network process is gone");
1290 _exit(EXIT_SUCCESS);
1291 }
1292#endif
1293
1294 m_networkProcessConnection = nullptr;
1295
1296 logDiagnosticMessageForNetworkProcessCrash();
1297
1298 m_webLoaderStrategy.networkProcessCrashed();
1299 WebSocketStream::networkProcessCrashed();
1300
1301 for (auto& page : m_pageMap.values()) {
1302 page->stopAllURLSchemeTasks();
1303#if ENABLE(APPLE_PAY)
1304 if (auto paymentCoordinator = page->paymentCoordinator())
1305 paymentCoordinator->networkProcessConnectionClosed();
1306#endif
1307 }
1308}
1309
1310WebLoaderStrategy& WebProcess::webLoaderStrategy()
1311{
1312 return m_webLoaderStrategy;
1313}
1314
1315void WebProcess::setEnhancedAccessibility(bool flag)
1316{
1317 WebCore::AXObjectCache::setEnhancedUserInterfaceAccessibility(flag);
1318}
1319
1320void WebProcess::startMemorySampler(SandboxExtension::Handle&& sampleLogFileHandle, const String& sampleLogFilePath, const double interval)
1321{
1322#if ENABLE(MEMORY_SAMPLER)
1323 WebMemorySampler::singleton()->start(WTFMove(sampleLogFileHandle), sampleLogFilePath, interval);
1324#else
1325 UNUSED_PARAM(sampleLogFileHandle);
1326 UNUSED_PARAM(sampleLogFilePath);
1327 UNUSED_PARAM(interval);
1328#endif
1329}
1330
1331void WebProcess::stopMemorySampler()
1332{
1333#if ENABLE(MEMORY_SAMPLER)
1334 WebMemorySampler::singleton()->stop();
1335#endif
1336}
1337
1338void WebProcess::setTextCheckerState(const TextCheckerState& textCheckerState)
1339{
1340 bool continuousSpellCheckingTurnedOff = !textCheckerState.isContinuousSpellCheckingEnabled && m_textCheckerState.isContinuousSpellCheckingEnabled;
1341 bool grammarCheckingTurnedOff = !textCheckerState.isGrammarCheckingEnabled && m_textCheckerState.isGrammarCheckingEnabled;
1342
1343 m_textCheckerState = textCheckerState;
1344
1345 if (!continuousSpellCheckingTurnedOff && !grammarCheckingTurnedOff)
1346 return;
1347
1348 for (auto& page : m_pageMap.values()) {
1349 if (continuousSpellCheckingTurnedOff)
1350 page->unmarkAllMisspellings();
1351 if (grammarCheckingTurnedOff)
1352 page->unmarkAllBadGrammar();
1353 }
1354}
1355
1356void WebProcess::releasePageCache()
1357{
1358 PageCache::singleton().pruneToSizeNow(0, PruningReason::MemoryPressure);
1359}
1360
1361void WebProcess::fetchWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, CompletionHandler<void(WebsiteData&&)>&& completionHandler)
1362{
1363 WebsiteData websiteData;
1364 if (websiteDataTypes.contains(WebsiteDataType::MemoryCache)) {
1365 for (auto& origin : MemoryCache::singleton().originsWithCache(sessionID))
1366 websiteData.entries.append(WebsiteData::Entry { origin->data(), WebsiteDataType::MemoryCache, 0 });
1367 }
1368 completionHandler(WTFMove(websiteData));
1369}
1370
1371void WebProcess::deleteWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, WallTime modifiedSince, CompletionHandler<void()>&& completionHandler)
1372{
1373 UNUSED_PARAM(modifiedSince);
1374
1375 if (websiteDataTypes.contains(WebsiteDataType::MemoryCache)) {
1376 PageCache::singleton().pruneToSizeNow(0, PruningReason::None);
1377 MemoryCache::singleton().evictResources(sessionID);
1378
1379 CrossOriginPreflightResultCache::singleton().clear();
1380 }
1381 completionHandler();
1382}
1383
1384void WebProcess::deleteWebsiteDataForOrigins(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, const Vector<WebCore::SecurityOriginData>& originDatas, CompletionHandler<void()>&& completionHandler)
1385{
1386 if (websiteDataTypes.contains(WebsiteDataType::MemoryCache)) {
1387 HashSet<RefPtr<SecurityOrigin>> origins;
1388 for (auto& originData : originDatas)
1389 origins.add(originData.securityOrigin());
1390
1391 MemoryCache::singleton().removeResourcesWithOrigins(sessionID, origins);
1392 }
1393 completionHandler();
1394}
1395
1396void WebProcess::setHiddenPageDOMTimerThrottlingIncreaseLimit(int milliseconds)
1397{
1398 for (auto& page : m_pageMap.values())
1399 page->setHiddenPageDOMTimerThrottlingIncreaseLimit(Seconds::fromMilliseconds(milliseconds));
1400}
1401
1402#if !PLATFORM(COCOA)
1403void WebProcess::initializeProcessName(const AuxiliaryProcessInitializationParameters&)
1404{
1405}
1406
1407void WebProcess::initializeSandbox(const AuxiliaryProcessInitializationParameters&, SandboxInitializationParameters&)
1408{
1409}
1410
1411void WebProcess::platformInitializeProcess(const AuxiliaryProcessInitializationParameters&)
1412{
1413}
1414
1415void WebProcess::updateActivePages()
1416{
1417}
1418
1419void WebProcess::getActivePagesOriginsForTesting(CompletionHandler<void(Vector<String>&&)>&& completionHandler)
1420{
1421 completionHandler({ });
1422}
1423
1424void WebProcess::updateCPULimit()
1425{
1426}
1427
1428void WebProcess::updateCPUMonitorState(CPUMonitorUpdateReason)
1429{
1430}
1431
1432#endif
1433
1434void WebProcess::pageActivityStateDidChange(uint64_t, OptionSet<WebCore::ActivityState::Flag> changed)
1435{
1436 if (changed & WebCore::ActivityState::IsVisible)
1437 updateCPUMonitorState(CPUMonitorUpdateReason::VisibilityHasChanged);
1438}
1439
1440#if PLATFORM(IOS_FAMILY)
1441void WebProcess::resetAllGeolocationPermissions()
1442{
1443 for (auto& page : m_pageMap.values()) {
1444 if (Frame* mainFrame = page->mainFrame())
1445 mainFrame->resetAllGeolocationPermission();
1446 }
1447}
1448#endif
1449
1450void WebProcess::actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend shouldAcknowledgeWhenReadyToSuspend)
1451{
1452 SetForScope<bool> suspensionScope(m_isSuspending, true);
1453 m_processIsSuspended = true;
1454
1455#if ENABLE(VIDEO)
1456 suspendAllMediaBuffering();
1457 PlatformMediaSessionManager::sharedManager().processWillSuspend();
1458#endif
1459
1460 if (!m_suppressMemoryPressureHandler)
1461 MemoryPressureHandler::singleton().releaseMemory(Critical::Yes, Synchronous::Yes);
1462
1463 freezeAllLayerTrees();
1464
1465#if PLATFORM(COCOA)
1466 destroyRenderingResources();
1467#endif
1468
1469#if PLATFORM(IOS_FAMILY)
1470 m_webSQLiteDatabaseTracker.setIsSuspended(true);
1471 SQLiteDatabase::setIsDatabaseOpeningForbidden(true);
1472 if (DatabaseTracker::isInitialized())
1473 DatabaseTracker::singleton().closeAllDatabases(CurrentQueryBehavior::Interrupt);
1474 accessibilityProcessSuspendedNotification(true);
1475 updateFreezerStatus();
1476#endif
1477
1478 markAllLayersVolatile([this, shouldAcknowledgeWhenReadyToSuspend](bool success) {
1479 if (success)
1480 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::markAllLayersVolatile() Successfuly marked all layers as volatile", this);
1481 else
1482 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::markAllLayersVolatile() Failed to mark all layers as volatile", this);
1483
1484 if (shouldAcknowledgeWhenReadyToSuspend == ShouldAcknowledgeWhenReadyToSuspend::Yes) {
1485 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::actualPrepareToSuspend() Sending ProcessReadyToSuspend IPC message", this);
1486 parentProcessConnection()->send(Messages::WebProcessProxy::ProcessReadyToSuspend(), 0);
1487 }
1488 });
1489}
1490
1491void WebProcess::processWillSuspendImminently()
1492{
1493 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::processWillSuspendImminently() BEGIN", this);
1494 actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend::No);
1495 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::processWillSuspendImminently() END", this);
1496}
1497
1498void WebProcess::prepareToSuspend()
1499{
1500 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::prepareToSuspend()", this);
1501 actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend::Yes);
1502}
1503
1504void WebProcess::cancelPrepareToSuspend()
1505{
1506 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::cancelPrepareToSuspend()", this);
1507
1508 m_processIsSuspended = false;
1509
1510 unfreezeAllLayerTrees();
1511
1512#if PLATFORM(IOS_FAMILY)
1513 m_webSQLiteDatabaseTracker.setIsSuspended(false);
1514 SQLiteDatabase::setIsDatabaseOpeningForbidden(false);
1515 accessibilityProcessSuspendedNotification(false);
1516#endif
1517
1518#if ENABLE(VIDEO)
1519 PlatformMediaSessionManager::sharedManager().processDidResume();
1520 resumeAllMediaBuffering();
1521#endif
1522
1523 // If we've already finished cleaning up and sent ProcessReadyToSuspend, we
1524 // shouldn't send DidCancelProcessSuspension; the UI process strictly expects one or the other.
1525 if (!m_pageMarkingLayersAsVolatileCounter)
1526 return;
1527
1528 cancelMarkAllLayersVolatile();
1529
1530 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::cancelPrepareToSuspend() Sending DidCancelProcessSuspension IPC message", this);
1531 parentProcessConnection()->send(Messages::WebProcessProxy::DidCancelProcessSuspension(), 0);
1532}
1533
1534void WebProcess::markAllLayersVolatile(WTF::Function<void(bool)>&& completionHandler)
1535{
1536 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::markAllLayersVolatile()", this);
1537 ASSERT(!m_pageMarkingLayersAsVolatileCounter);
1538 m_countOfPagesFailingToMarkVolatile = 0;
1539
1540 m_pageMarkingLayersAsVolatileCounter = std::make_unique<PageMarkingLayersAsVolatileCounter>([this, completionHandler = WTFMove(completionHandler)] (RefCounterEvent) {
1541 if (m_pageMarkingLayersAsVolatileCounter->value())
1542 return;
1543
1544 completionHandler(m_countOfPagesFailingToMarkVolatile == 0);
1545 m_pageMarkingLayersAsVolatileCounter = nullptr;
1546 });
1547 auto token = m_pageMarkingLayersAsVolatileCounter->count();
1548 for (auto& page : m_pageMap.values())
1549 page->markLayersVolatile([token, this] (bool succeeded) {
1550 if (!succeeded)
1551 ++m_countOfPagesFailingToMarkVolatile;
1552 });
1553}
1554
1555void WebProcess::cancelMarkAllLayersVolatile()
1556{
1557 if (!m_pageMarkingLayersAsVolatileCounter)
1558 return;
1559
1560 m_pageMarkingLayersAsVolatileCounter = nullptr;
1561 for (auto& page : m_pageMap.values())
1562 page->cancelMarkLayersVolatile();
1563}
1564
1565void WebProcess::freezeAllLayerTrees()
1566{
1567 RELEASE_LOG(ProcessSuspension, "WebProcess %i is freezing all layer trees", getpid());
1568 for (auto& page : m_pageMap.values())
1569 page->freezeLayerTree(WebPage::LayerTreeFreezeReason::ProcessSuspended);
1570}
1571
1572void WebProcess::unfreezeAllLayerTrees()
1573{
1574 RELEASE_LOG(ProcessSuspension, "WebProcess %i is unfreezing all layer trees", getpid());
1575 for (auto& page : m_pageMap.values())
1576 page->unfreezeLayerTree(WebPage::LayerTreeFreezeReason::ProcessSuspended);
1577}
1578
1579void WebProcess::processDidResume()
1580{
1581 RELEASE_LOG(ProcessSuspension, "%p - WebProcess::processDidResume()", this);
1582
1583 m_processIsSuspended = false;
1584
1585 cancelMarkAllLayersVolatile();
1586 unfreezeAllLayerTrees();
1587
1588#if PLATFORM(IOS_FAMILY)
1589 m_webSQLiteDatabaseTracker.setIsSuspended(false);
1590 SQLiteDatabase::setIsDatabaseOpeningForbidden(false);
1591 accessibilityProcessSuspendedNotification(false);
1592#endif
1593
1594#if ENABLE(VIDEO)
1595 PlatformMediaSessionManager::sharedManager().processDidResume();
1596 resumeAllMediaBuffering();
1597#endif
1598}
1599
1600void WebProcess::sendPrewarmInformation(const URL& url)
1601{
1602 auto registrableDomain = WebCore::RegistrableDomain { url };
1603 if (registrableDomain.isEmpty())
1604 return;
1605 parentProcessConnection()->send(Messages::WebProcessProxy::DidCollectPrewarmInformation(registrableDomain, WebCore::ProcessWarming::collectPrewarmInformation()), 0);
1606}
1607
1608void WebProcess::pageDidEnterWindow(uint64_t pageID)
1609{
1610 m_pagesInWindows.add(pageID);
1611 m_nonVisibleProcessCleanupTimer.stop();
1612}
1613
1614void WebProcess::pageWillLeaveWindow(uint64_t pageID)
1615{
1616 m_pagesInWindows.remove(pageID);
1617
1618 if (m_pagesInWindows.isEmpty() && !m_nonVisibleProcessCleanupTimer.isActive())
1619 m_nonVisibleProcessCleanupTimer.startOneShot(nonVisibleProcessCleanupDelay);
1620}
1621
1622void WebProcess::nonVisibleProcessCleanupTimerFired()
1623{
1624 ASSERT(m_pagesInWindows.isEmpty());
1625 if (!m_pagesInWindows.isEmpty())
1626 return;
1627
1628#if PLATFORM(COCOA)
1629 destroyRenderingResources();
1630#endif
1631}
1632
1633void WebProcess::setResourceLoadStatisticsEnabled(bool enabled)
1634{
1635 WebCore::DeprecatedGlobalSettings::setResourceLoadStatisticsEnabled(enabled);
1636}
1637
1638void WebProcess::clearResourceLoadStatistics()
1639{
1640 ResourceLoadObserver::shared().clearState();
1641}
1642
1643RefPtr<API::Object> WebProcess::transformHandlesToObjects(API::Object* object)
1644{
1645 struct Transformer final : UserData::Transformer {
1646 Transformer(WebProcess& webProcess)
1647 : m_webProcess(webProcess)
1648 {
1649 }
1650
1651 bool shouldTransformObject(const API::Object& object) const override
1652 {
1653 switch (object.type()) {
1654 case API::Object::Type::FrameHandle:
1655 return static_cast<const API::FrameHandle&>(object).isAutoconverting();
1656
1657 case API::Object::Type::PageHandle:
1658 return static_cast<const API::PageHandle&>(object).isAutoconverting();
1659
1660 case API::Object::Type::PageGroupHandle:
1661#if PLATFORM(COCOA)
1662 case API::Object::Type::ObjCObjectGraph:
1663#endif
1664 return true;
1665
1666 default:
1667 return false;
1668 }
1669 }
1670
1671 RefPtr<API::Object> transformObject(API::Object& object) const override
1672 {
1673 switch (object.type()) {
1674 case API::Object::Type::FrameHandle:
1675 return m_webProcess.webFrame(static_cast<const API::FrameHandle&>(object).frameID());
1676
1677 case API::Object::Type::PageGroupHandle:
1678 return m_webProcess.webPageGroup(static_cast<const API::PageGroupHandle&>(object).webPageGroupData());
1679
1680 case API::Object::Type::PageHandle:
1681 return m_webProcess.webPage(static_cast<const API::PageHandle&>(object).pageID());
1682
1683#if PLATFORM(COCOA)
1684 case API::Object::Type::ObjCObjectGraph:
1685 return m_webProcess.transformHandlesToObjects(static_cast<ObjCObjectGraph&>(object));
1686#endif
1687 default:
1688 return &object;
1689 }
1690 }
1691
1692 WebProcess& m_webProcess;
1693 };
1694
1695 return UserData::transform(object, Transformer(*this));
1696}
1697
1698RefPtr<API::Object> WebProcess::transformObjectsToHandles(API::Object* object)
1699{
1700 struct Transformer final : UserData::Transformer {
1701 bool shouldTransformObject(const API::Object& object) const override
1702 {
1703 switch (object.type()) {
1704 case API::Object::Type::BundleFrame:
1705 case API::Object::Type::BundlePage:
1706 case API::Object::Type::BundlePageGroup:
1707#if PLATFORM(COCOA)
1708 case API::Object::Type::ObjCObjectGraph:
1709#endif
1710 return true;
1711
1712 default:
1713 return false;
1714 }
1715 }
1716
1717 RefPtr<API::Object> transformObject(API::Object& object) const override
1718 {
1719 switch (object.type()) {
1720 case API::Object::Type::BundleFrame:
1721 return API::FrameHandle::createAutoconverting(static_cast<const WebFrame&>(object).frameID());
1722
1723 case API::Object::Type::BundlePage:
1724 return API::PageHandle::createAutoconverting(static_cast<const WebPage&>(object).pageID());
1725
1726 case API::Object::Type::BundlePageGroup: {
1727 WebPageGroupData pageGroupData;
1728 pageGroupData.pageGroupID = static_cast<const WebPageGroupProxy&>(object).pageGroupID();
1729
1730 return API::PageGroupHandle::create(WTFMove(pageGroupData));
1731 }
1732
1733#if PLATFORM(COCOA)
1734 case API::Object::Type::ObjCObjectGraph:
1735 return transformObjectsToHandles(static_cast<ObjCObjectGraph&>(object));
1736#endif
1737
1738 default:
1739 return &object;
1740 }
1741 }
1742 };
1743
1744 return UserData::transform(object, Transformer());
1745}
1746
1747void WebProcess::setMemoryCacheDisabled(bool disabled)
1748{
1749 auto& memoryCache = MemoryCache::singleton();
1750 if (memoryCache.disabled() != disabled)
1751 memoryCache.setDisabled(disabled);
1752}
1753
1754#if ENABLE(SERVICE_CONTROLS)
1755void WebProcess::setEnabledServices(bool hasImageServices, bool hasSelectionServices, bool hasRichContentServices)
1756{
1757 m_hasImageServices = hasImageServices;
1758 m_hasSelectionServices = hasSelectionServices;
1759 m_hasRichContentServices = hasRichContentServices;
1760}
1761#endif
1762
1763void WebProcess::ensureAutomationSessionProxy(const String& sessionIdentifier)
1764{
1765 m_automationSessionProxy = std::make_unique<WebAutomationSessionProxy>(sessionIdentifier);
1766}
1767
1768void WebProcess::destroyAutomationSessionProxy()
1769{
1770 m_automationSessionProxy = nullptr;
1771}
1772
1773void WebProcess::prefetchDNS(const String& hostname)
1774{
1775 if (hostname.isEmpty())
1776 return;
1777
1778 if (m_dnsPrefetchedHosts.add(hostname).isNewEntry)
1779 ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::PrefetchDNS(hostname), 0);
1780 // The DNS prefetched hosts cache is only to avoid asking for the same hosts too many times
1781 // in a very short period of time, producing a lot of IPC traffic. So we clear this cache after
1782 // some time of no DNS requests.
1783 m_dnsPrefetchHystereris.impulse();
1784}
1785
1786bool WebProcess::hasVisibleWebPage() const
1787{
1788 for (auto& page : m_pageMap.values()) {
1789 if (page->isVisible())
1790 return true;
1791 }
1792 return false;
1793}
1794
1795LibWebRTCNetwork& WebProcess::libWebRTCNetwork()
1796{
1797 if (!m_libWebRTCNetwork)
1798 m_libWebRTCNetwork = std::make_unique<LibWebRTCNetwork>();
1799 return *m_libWebRTCNetwork;
1800}
1801
1802#if ENABLE(SERVICE_WORKER)
1803void WebProcess::establishWorkerContextConnectionToNetworkProcess(uint64_t pageGroupID, uint64_t pageID, const WebPreferencesStore& store, PAL::SessionID initialSessionID)
1804{
1805 // We are in the Service Worker context process and the call below establishes our connection to the Network Process
1806 // by calling ensureNetworkProcessConnection. SWContextManager needs to use the same underlying IPC::Connection as the
1807 // NetworkProcessConnection for synchronization purposes.
1808 auto& ipcConnection = ensureNetworkProcessConnection().connection();
1809 SWContextManager::singleton().setConnection(std::make_unique<WebSWContextManagerConnection>(ipcConnection, pageGroupID, pageID, store));
1810}
1811
1812void WebProcess::registerServiceWorkerClients()
1813{
1814 // We do not want to register service worker dummy documents.
1815 ASSERT(!SWContextManager::singleton().connection());
1816 ServiceWorkerProvider::singleton().registerServiceWorkerClients();
1817}
1818
1819#endif
1820
1821#if PLATFORM(MAC)
1822void WebProcess::setScreenProperties(const WebCore::ScreenProperties& properties)
1823{
1824 WebCore::setScreenProperties(properties);
1825}
1826#endif
1827
1828#if ENABLE(MEDIA_STREAM)
1829void WebProcess::addMockMediaDevice(const WebCore::MockMediaDevice& device)
1830{
1831 MockRealtimeMediaSourceCenter::addDevice(device);
1832}
1833
1834void WebProcess::clearMockMediaDevices()
1835{
1836 MockRealtimeMediaSourceCenter::setDevices({ });
1837}
1838
1839void WebProcess::removeMockMediaDevice(const String& persistentId)
1840{
1841 MockRealtimeMediaSourceCenter::removeDevice(persistentId);
1842}
1843
1844void WebProcess::resetMockMediaDevices()
1845{
1846 MockRealtimeMediaSourceCenter::resetDevices();
1847}
1848
1849#if ENABLE(SANDBOX_EXTENSIONS)
1850void WebProcess::grantUserMediaDeviceSandboxExtensions(MediaDeviceSandboxExtensions&& extensions)
1851{
1852 for (size_t i = 0; i < extensions.size(); i++) {
1853 const auto& extension = extensions[i];
1854 extension.second->consume();
1855 RELEASE_LOG(WebRTC, "UserMediaPermissionRequestManager::grantUserMediaDeviceSandboxExtensions - granted extension %s", extension.first.utf8().data());
1856 m_mediaCaptureSandboxExtensions.add(extension.first, extension.second.copyRef());
1857 }
1858}
1859
1860static inline void checkDocumentsCaptureStateConsistency(const Vector<String>& extensionIDs)
1861{
1862#if !ASSERT_DISABLED
1863 bool isCapturingAudio = WTF::anyOf(Document::allDocumentsMap().values(), [](auto* document) {
1864 return document->mediaState() & MediaProducer::AudioCaptureMask;
1865 });
1866 bool isCapturingVideo = WTF::anyOf(Document::allDocumentsMap().values(), [](auto* document) {
1867 return document->mediaState() & MediaProducer::VideoCaptureMask;
1868 });
1869
1870 if (isCapturingAudio)
1871 ASSERT(extensionIDs.findMatching([](auto& id) { return id.contains("microphone"); }) == notFound);
1872 if (isCapturingVideo)
1873 ASSERT(extensionIDs.findMatching([](auto& id) { return id.contains("camera"); }) == notFound);
1874#endif
1875}
1876
1877void WebProcess::revokeUserMediaDeviceSandboxExtensions(const Vector<String>& extensionIDs)
1878{
1879 checkDocumentsCaptureStateConsistency(extensionIDs);
1880
1881 for (const auto& extensionID : extensionIDs) {
1882 auto extension = m_mediaCaptureSandboxExtensions.take(extensionID);
1883 ASSERT(extension || MockRealtimeMediaSourceCenter::mockRealtimeMediaSourceCenterEnabled());
1884 if (extension) {
1885 extension->revoke();
1886 RELEASE_LOG(WebRTC, "UserMediaPermissionRequestManager::revokeUserMediaDeviceSandboxExtensions - revoked extension %s", extensionID.utf8().data());
1887 }
1888 }
1889}
1890#endif
1891#endif
1892
1893#if ENABLE(VIDEO)
1894void WebProcess::suspendAllMediaBuffering()
1895{
1896 for (auto& page : m_pageMap.values())
1897 page->suspendAllMediaBuffering();
1898}
1899
1900void WebProcess::resumeAllMediaBuffering()
1901{
1902 for (auto& page : m_pageMap.values())
1903 page->resumeAllMediaBuffering();
1904}
1905#endif
1906
1907void WebProcess::clearCurrentModifierStateForTesting()
1908{
1909 PlatformKeyboardEvent::setCurrentModifierState({ });
1910}
1911
1912#if PLATFORM(IOS_FAMILY)
1913void WebProcess::unblockAccessibilityServer(const SandboxExtension::Handle& handle)
1914{
1915 bool ok = SandboxExtension::consumePermanently(handle);
1916 ASSERT_UNUSED(ok, ok);
1917}
1918#endif
1919
1920bool WebProcess::areAllPagesThrottleable() const
1921{
1922 return WTF::allOf(m_pageMap.values(), [](auto& page) {
1923 return page->isThrottleable();
1924 });
1925}
1926
1927} // namespace WebKit
1928