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