/* * Copyright (C) 2009-2022 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "WebProcess.h" #include "APIFrameHandle.h" #include "APIPageHandle.h" #include "AudioMediaStreamTrackRendererInternalUnitManager.h" #include "AuthenticationManager.h" #include "AuxiliaryProcessMessages.h" #include "DrawingArea.h" #include "EventDispatcher.h" #include "GPUProcessConnectionParameters.h" #include "InjectedBundle.h" #include "LibWebRTCNetwork.h" #include "Logging.h" #include "NetworkConnectionToWebProcessMessages.h" #include "NetworkProcessConnection.h" #include "NetworkProcessConnectionInfo.h" #include "NetworkSession.h" #include "NetworkSessionCreationParameters.h" #include "ProcessAssertion.h" #include "RemoteAudioHardwareListener.h" #include "RemoteAudioSession.h" #include "RemoteLegacyCDMFactory.h" #include "RemoteMediaEngineConfigurationFactory.h" #include "RemoteRemoteCommandListener.h" #include "RemoteWebLockRegistry.h" #include "SpeechRecognitionRealtimeMediaSourceManager.h" #include "StorageAreaMap.h" #include "UserData.h" #include "WebAutomationSessionProxy.h" #include "WebBroadcastChannelRegistry.h" #include "WebCacheStorageProvider.h" #include "WebConnectionToUIProcess.h" #include "WebCookieJar.h" #include "WebCoreArgumentCoders.h" #include "WebFileSystemStorageConnection.h" #include "WebFrame.h" #include "WebFrameNetworkingContext.h" #include "WebGamepadProvider.h" #include "WebGeolocationManager.h" #include "WebIDBConnectionToServer.h" #include "WebLoaderStrategy.h" #include "WebMediaKeyStorageManager.h" #include "WebMemorySampler.h" #include "WebMessagePortChannelProvider.h" #include "WebPage.h" #include "WebPageCreationParameters.h" #include "WebPageGroupProxy.h" #include "WebPaymentCoordinator.h" #include "WebPlatformStrategies.h" #include "WebPluginInfoProvider.h" #include "WebProcessCreationParameters.h" #include "WebProcessDataStoreParameters.h" #include "WebProcessMessages.h" #include "WebProcessPoolMessages.h" #include "WebProcessProxyMessages.h" #include "WebResourceLoadObserver.h" #include "WebSWClientConnection.h" #include "WebSWContextManagerConnection.h" #include "WebSWContextManagerConnectionMessages.h" #include "WebServiceWorkerProvider.h" #include "WebSocketStream.h" #include "WebsiteData.h" #include "WebsiteDataStoreParameters.h" #include "WebsiteDataType.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if ENABLE(ARKIT_INLINE_PREVIEW_MAC) #include "ARKitInlinePreviewModelPlayerMac.h" #endif #if !OS(WINDOWS) #include #endif #if PLATFORM(WAYLAND) #include "WaylandCompositorDisplay.h" #endif #if PLATFORM(COCOA) #include "ObjCObjectGraph.h" #include "UserMediaCaptureManager.h" #endif #if PLATFORM(MAC) #include #endif #if PLATFORM(IOS_FAMILY) #include "WebSQLiteDatabaseTracker.h" #endif #if ENABLE(SEC_ITEM_SHIM) #include "SecItemShim.h" #endif #if ENABLE(NOTIFICATIONS) #include "WebNotificationManager.h" #endif #if ENABLE(GPU_PROCESS) #include "GPUConnectionToWebProcessMessages.h" #include "GPUProcessConnection.h" #include "GPUProcessConnectionInfo.h" #endif #if ENABLE(WEB_AUTHN) #include "WebAuthnConnectionToWebProcessMessages.h" #include "WebAuthnProcessConnection.h" #include "WebAuthnProcessConnectionInfo.h" #endif #if ENABLE(REMOTE_INSPECTOR) #include #endif #if ENABLE(GPU_PROCESS) #include "RemoteMediaPlayerManager.h" #endif #if USE(LIBWEBRTC) && PLATFORM(COCOA) && ENABLE(GPU_PROCESS) #include "LibWebRTCCodecs.h" #endif #if ENABLE(ENCRYPTED_MEDIA) #include "RemoteCDMFactory.h" #endif #if PLATFORM(IOS_FAMILY) #include "RemoteMediaSessionHelper.h" #endif #if ENABLE(ROUTING_ARBITRATION) #include "AudioSessionRoutingArbitrator.h" #endif #if ENABLE(GPU_PROCESS) && HAVE(AVASSETREADER) #include "RemoteImageDecoderAVF.h" #include #endif #if PLATFORM(COCOA) #include #include #endif #if OS(LINUX) #include #endif #undef WEBPROCESS_RELEASE_LOG #define RELEASE_LOG_SESSION_ID (m_sessionID ? m_sessionID->toUInt64() : 0) #if RELEASE_LOG_DISABLED #define WEBPROCESS_RELEASE_LOG(channel, fmt, ...) UNUSED_VARIABLE(this) #define WEBPROCESS_RELEASE_LOG_ERROR(channel, fmt, ...) UNUSED_VARIABLE(this) #else #define WEBPROCESS_RELEASE_LOG(channel, fmt, ...) RELEASE_LOG(channel, "%p - [sessionID=%" PRIu64 "] WebProcess::" fmt, this, RELEASE_LOG_SESSION_ID, ##__VA_ARGS__) #define WEBPROCESS_RELEASE_LOG_ERROR(channel, fmt, ...) RELEASE_LOG_ERROR(channel, "%p - [sessionID=%" PRIu64 "] WebProcess::" fmt, this, RELEASE_LOG_SESSION_ID, ##__VA_ARGS__) #endif // This should be less than plugInAutoStartExpirationTimeThreshold in PlugInAutoStartProvider. static const Seconds plugInAutoStartExpirationTimeUpdateThreshold { 29 * 24 * 60 * 60 }; // This should be greater than tileRevalidationTimeout in TileController. static const Seconds nonVisibleProcessGraphicsCleanupDelay { 10_s }; #if ENABLE(NON_VISIBLE_WEBPROCESS_MEMORY_CLEANUP_TIMER) // This should be long enough to support a workload where a user is actively switching between multiple tabs, // since our memory cleanup routine could potentially delete a good amount of JIT code. static const Seconds nonVisibleProcessMemoryCleanupDelay { 120_s }; #endif namespace WebKit { using namespace JSC; using namespace WebCore; NO_RETURN static void callExit(IPC::Connection*) { #if OS(WINDOWS) // Calling _exit in non-main threads may cause a deadlock in WTF::Thread::ThreadHolder::~ThreadHolder. TerminateProcess(GetCurrentProcess(), EXIT_SUCCESS); #else _exit(EXIT_SUCCESS); #endif } WebProcess& WebProcess::singleton() { static WebProcess& process = *new WebProcess; return process; } WebProcess::WebProcess() : m_eventDispatcher(EventDispatcher::create()) #if PLATFORM(IOS_FAMILY) , m_viewUpdateDispatcher(ViewUpdateDispatcher::create()) #endif , m_webInspectorInterruptDispatcher(WebInspectorInterruptDispatcher::create()) , m_webLoaderStrategy(*new WebLoaderStrategy) , m_cacheStorageProvider(WebCacheStorageProvider::create()) , m_broadcastChannelRegistry(WebBroadcastChannelRegistry::create()) , m_webLockRegistry(RemoteWebLockRegistry::create(*this)) , m_cookieJar(WebCookieJar::create()) , m_dnsPrefetchHystereris([this](PAL::HysteresisState state) { if (state == PAL::HysteresisState::Stopped) m_dnsPrefetchedHosts.clear(); }) , m_nonVisibleProcessGraphicsCleanupTimer(*this, &WebProcess::nonVisibleProcessGraphicsCleanupTimerFired) #if ENABLE(NON_VISIBLE_WEBPROCESS_MEMORY_CLEANUP_TIMER) , m_nonVisibleProcessMemoryCleanupTimer(*this, &WebProcess::nonVisibleProcessMemoryCleanupTimerFired) #endif #if PLATFORM(IOS_FAMILY) , m_webSQLiteDatabaseTracker([this](bool isHoldingLockedFiles) { parentProcessConnection()->send(Messages::WebProcessProxy::SetIsHoldingLockedFiles(isHoldingLockedFiles), 0); }) #endif { // Initialize our platform strategies. WebPlatformStrategies::initialize(); // FIXME: This should moved to where WebProcess::initialize is called, // so that ports have a chance to customize, and ifdefs in this file are // limited. addSupplement(); #if ENABLE(NOTIFICATIONS) addSupplement(); #endif #if ENABLE(LEGACY_ENCRYPTED_MEDIA) addSupplement(); #endif #if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) addSupplement(); #endif #if ENABLE(GPU_PROCESS) addSupplement(); #endif #if ENABLE(GPU_PROCESS) && HAVE(AVASSETREADER) addSupplement(); #endif #if ENABLE(GPU_PROCESS) && ENABLE(ENCRYPTED_MEDIA) addSupplement(); #endif #if ENABLE(GPU_PROCESS) && ENABLE(LEGACY_ENCRYPTED_MEDIA) addSupplement(); #endif #if ENABLE(ROUTING_ARBITRATION) addSupplement(); #endif #if ENABLE(GPU_PROCESS) addSupplement(); #endif Gigacage::forbidDisablingPrimitiveGigacage(); } WebProcess::~WebProcess() { ASSERT_NOT_REACHED(); } void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameters& parameters) { WTF::setProcessPrivileges({ }); MessagePortChannelProvider::setSharedProvider(WebMessagePortChannelProvider::singleton()); platformInitializeProcess(parameters); updateCPULimit(); } void WebProcess::initializeConnection(IPC::Connection* connection) { AuxiliaryProcess::initializeConnection(connection); // We call _exit() directly from the background queue in case the main thread is unresponsive // and AuxiliaryProcess::didClose() does not get called. connection->setDidCloseOnConnectionWorkQueueCallback(callExit); #if !PLATFORM(GTK) && !PLATFORM(WPE) && !ENABLE(IPC_TESTING_API) connection->setShouldExitOnSyncMessageSendFailure(true); #endif m_eventDispatcher->initializeConnection(connection); #if PLATFORM(IOS_FAMILY) m_viewUpdateDispatcher->initializeConnection(connection); #endif // PLATFORM(IOS_FAMILY) m_webInspectorInterruptDispatcher->initializeConnection(connection); for (auto& supplement : m_supplements.values()) supplement->initializeConnection(connection); m_webConnection = WebConnectionToUIProcess::create(this); } static void scheduleLogMemoryStatistics(LogMemoryStatisticsReason reason) { // Log stats in the next turn of the run loop so that it runs after the low memory handler. RunLoop::main().dispatch([reason] { WebCore::logMemoryStatistics(reason); }); } void WebProcess::initializeWebProcess(WebProcessCreationParameters&& parameters) { TraceScope traceScope(InitializeWebProcessStart, InitializeWebProcessEnd); ASSERT(m_pageMap.isEmpty()); if (parameters.websiteDataStoreParameters) setWebsiteDataStoreParameters(WTFMove(*parameters.websiteDataStoreParameters)); WebCore::setPresentingApplicationPID(parameters.presentingApplicationPID); #if OS(LINUX) MemoryPressureHandler::ReliefLogger::setLoggingEnabled(parameters.shouldEnableMemoryPressureReliefLogging); #endif platformInitializeWebProcess(parameters); // Match the QoS of the UIProcess and the scrolling thread but use a slightly lower priority. WTF::Thread::setCurrentThreadIsUserInteractive(-1); m_suppressMemoryPressureHandler = parameters.shouldSuppressMemoryPressureHandler; if (!m_suppressMemoryPressureHandler) { auto& memoryPressureHandler = MemoryPressureHandler::singleton(); memoryPressureHandler.setLowMemoryHandler([this] (Critical critical, Synchronous synchronous) { // If this process contains only non-visible content (e.g. only contains background // tabs), then treat the memory warning as if it was a critical warning to maximize the // amount of memory released for foreground apps to use. if (m_pagesInWindows.isEmpty() && critical == Critical::No) critical = Critical::Yes; #if PLATFORM(MAC) // If this is a process we keep around for performance, kill it on memory pressure instead of trying to free up its memory. if (m_processType == ProcessType::CachedWebContent || m_processType == ProcessType::PrewarmedWebContent || areAllPagesSuspended()) { if (m_processType == ProcessType::CachedWebContent) WEBPROCESS_RELEASE_LOG(Process, "initializeWebProcess: Cached WebProcess is exiting due to memory pressure"); else if (m_processType == ProcessType::PrewarmedWebContent) WEBPROCESS_RELEASE_LOG(Process, "initializeWebProcess: Prewarmed WebProcess is exiting due to memory pressure"); else WEBPROCESS_RELEASE_LOG(Process, "initializeWebProcess: Suspended WebProcess is exiting due to memory pressure"); stopRunLoop(); return; } #endif auto maintainBackForwardCache = m_isSuspending ? WebCore::MaintainBackForwardCache::Yes : WebCore::MaintainBackForwardCache::No; auto maintainMemoryCache = m_isSuspending && m_hasSuspendedPageProxy ? WebCore::MaintainMemoryCache::Yes : WebCore::MaintainMemoryCache::No; WebCore::releaseMemory(critical, synchronous, maintainBackForwardCache, maintainMemoryCache); for (auto& page : m_pageMap.values()) page->releaseMemory(critical); }); #if ENABLE(PERIODIC_MEMORY_MONITOR) memoryPressureHandler.setShouldUsePeriodicMemoryMonitor(true); memoryPressureHandler.setMemoryKillCallback([this] () { WebCore::logMemoryStatistics(LogMemoryStatisticsReason::OutOfMemoryDeath); if (MemoryPressureHandler::singleton().processState() == WebsamProcessState::Active) parentProcessConnection()->send(Messages::WebProcessProxy::DidExceedActiveMemoryLimit(), 0); else parentProcessConnection()->send(Messages::WebProcessProxy::DidExceedInactiveMemoryLimit(), 0); }); memoryPressureHandler.setDidExceedInactiveLimitWhileActiveCallback([this] () { parentProcessConnection()->send(Messages::WebProcessProxy::DidExceedInactiveMemoryLimitWhileActive(), 0); if (!m_loggedProcessLimitCriticalMemoryStatistics) { m_loggedProcessLimitCriticalMemoryStatistics = true; scheduleLogMemoryStatistics(LogMemoryStatisticsReason::CriticalMemoryPressureNotification); } }); #endif memoryPressureHandler.setMemoryPressureStatusChangedCallback([this](WTF::MemoryPressureStatus memoryPressureStatus) { if (parentProcessConnection()) parentProcessConnection()->send(Messages::WebProcessProxy::MemoryPressureStatusChanged(MemoryPressureHandler::singleton().isUnderMemoryPressure()), 0); if (memoryPressureStatus == WTF::MemoryPressureStatus::ProcessLimitWarning && !m_loggedProcessLimitWarningMemoryStatistics) { m_loggedProcessLimitWarningMemoryStatistics = true; scheduleLogMemoryStatistics(LogMemoryStatisticsReason::WarningMemoryPressureNotification); } else if (memoryPressureStatus == WTF::MemoryPressureStatus::ProcessLimitCritical && !m_loggedProcessLimitCriticalMemoryStatistics) { m_loggedProcessLimitCriticalMemoryStatistics = true; scheduleLogMemoryStatistics(LogMemoryStatisticsReason::CriticalMemoryPressureNotification); } }); memoryPressureHandler.install(); PAL::registerNotifyCallback("com.apple.WebKit.logMemStats", [] { WebCore::logMemoryStatistics(LogMemoryStatisticsReason::DebugNotification); }); } SandboxExtension::consumePermanently(parameters.additionalSandboxExtensionHandles); if (!parameters.injectedBundlePath.isEmpty()) m_injectedBundle = InjectedBundle::create(parameters, transformHandlesToObjects(parameters.initializationUserData.object()).get()); for (auto& supplement : m_supplements.values()) supplement->initialize(parameters); setCacheModel(parameters.cacheModel); if (!parameters.overrideLanguages.isEmpty()) { LOG_WITH_STREAM(Language, stream << "Web Process initialization is setting overrideLanguages: " << parameters.overrideLanguages); overrideUserPreferredLanguages(parameters.overrideLanguages); } else LOG(Language, "Web process initialization is not setting overrideLanguages"); m_textCheckerState = parameters.textCheckerState; m_fullKeyboardAccessEnabled = parameters.fullKeyboardAccessEnabled; #if HAVE(MOUSE_DEVICE_OBSERVATION) m_hasMouseDevice = parameters.hasMouseDevice; #endif #if HAVE(STYLUS_DEVICE_OBSERVATION) m_hasStylusDevice = parameters.hasStylusDevice; #endif for (auto& scheme : parameters.urlSchemesRegisteredAsEmptyDocument) registerURLSchemeAsEmptyDocument(scheme); for (auto& scheme : parameters.urlSchemesRegisteredAsSecure) registerURLSchemeAsSecure(scheme); for (auto& scheme : parameters.urlSchemesRegisteredAsBypassingContentSecurityPolicy) registerURLSchemeAsBypassingContentSecurityPolicy(scheme); for (auto& scheme : parameters.urlSchemesForWhichDomainRelaxationIsForbidden) setDomainRelaxationForbiddenForURLScheme(scheme); for (auto& scheme : parameters.urlSchemesRegisteredAsLocal) registerURLSchemeAsLocal(scheme); for (auto& scheme : parameters.urlSchemesRegisteredAsNoAccess) registerURLSchemeAsNoAccess(scheme); for (auto& scheme : parameters.urlSchemesRegisteredAsDisplayIsolated) registerURLSchemeAsDisplayIsolated(scheme); for (auto& scheme : parameters.urlSchemesRegisteredAsCORSEnabled) LegacySchemeRegistry::registerURLSchemeAsCORSEnabled(scheme); for (auto& scheme : parameters.urlSchemesRegisteredAsAlwaysRevalidated) registerURLSchemeAsAlwaysRevalidated(scheme); for (auto& scheme : parameters.urlSchemesRegisteredAsCachePartitioned) registerURLSchemeAsCachePartitioned(scheme); for (auto& scheme : parameters.urlSchemesRegisteredAsCanDisplayOnlyIfCanRequest) registerURLSchemeAsCanDisplayOnlyIfCanRequest(scheme); setDefaultRequestTimeoutInterval(parameters.defaultRequestTimeoutInterval); setBackForwardCacheCapacity(parameters.backForwardCacheCapacity); setAlwaysUsesComplexTextCodePath(parameters.shouldAlwaysUseComplexTextCodePath); setShouldUseFontSmoothing(parameters.shouldUseFontSmoothing); setTerminationTimeout(parameters.terminationTimeout); setMemoryCacheDisabled(parameters.memoryCacheDisabled); WebCore::RuntimeEnabledFeatures::sharedFeatures().setAttrStyleEnabled(parameters.attrStyleEnabled); commonVM().setGlobalConstRedeclarationShouldThrow(parameters.shouldThrowExceptionForGlobalConstantRedeclaration); ScriptExecutionContext::setCrossOriginMode(parameters.crossOriginMode); m_isCaptivePortalModeEnabled = parameters.isCaptivePortalModeEnabled; #if ENABLE(SERVICE_CONTROLS) setEnabledServices(parameters.hasImageServices, parameters.hasSelectionServices, parameters.hasRichContentServices); #endif #if ENABLE(REMOTE_INSPECTOR) && PLATFORM(COCOA) if (std::optional auditToken = parentProcessConnection()->getAuditToken()) { RetainPtr auditData = adoptCF(CFDataCreate(nullptr, (const UInt8*)&*auditToken, sizeof(*auditToken))); Inspector::RemoteInspector::singleton().setParentProcessInformation(WebCore::presentingApplicationPID(), auditData); } #endif #if ENABLE(GAMEPAD) GamepadProvider::singleton().setSharedProvider(WebGamepadProvider::singleton()); #endif #if ENABLE(SERVICE_WORKER) ServiceWorkerProvider::setSharedProvider(WebServiceWorkerProvider::singleton()); #endif #if ENABLE(WEBASSEMBLY) JSC::Wasm::enableFastMemory(); #endif #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) && !RELEASE_LOG_DISABLED WebResourceLoadObserver::setShouldLogUserInteraction(parameters.shouldLogUserInteraction); #endif #if PLATFORM(COCOA) if (m_processType == ProcessType::PrewarmedWebContent) prewarmGlobally(); #endif WEBPROCESS_RELEASE_LOG(Process, "initializeWebProcess: Presenting processPID=%d", WebCore::presentingApplicationPID()); } void WebProcess::setWebsiteDataStoreParameters(WebProcessDataStoreParameters&& parameters) { ASSERT(!m_sessionID); m_sessionID = parameters.sessionID; // FIXME: This should be constructed per data store, not per process. m_applicationCacheStorage = ApplicationCacheStorage::create(parameters.applicationCacheDirectory, parameters.applicationCacheFlatFileSubdirectoryName); #if PLATFORM(IOS_FAMILY) m_applicationCacheStorage->setDefaultOriginQuota(25ULL * 1024 * 1024); #endif #if ENABLE(VIDEO) if (!parameters.mediaCacheDirectory.isEmpty()) WebCore::HTMLMediaElement::setMediaCacheDirectory(parameters.mediaCacheDirectory); #endif #if ENABLE(ARKIT_INLINE_PREVIEW_MAC) if (!parameters.modelElementCacheDirectory.isEmpty()) ARKitInlinePreviewModelPlayerMac::setModelElementCacheDirectory(parameters.modelElementCacheDirectory); #endif setResourceLoadStatisticsEnabled(parameters.resourceLoadStatisticsEnabled); #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) m_thirdPartyCookieBlockingMode = parameters.thirdPartyCookieBlockingMode; if (parameters.resourceLoadStatisticsEnabled) { if (!ResourceLoadObserver::sharedIfExists()) ResourceLoadObserver::setShared(*new WebResourceLoadObserver(parameters.sessionID.isEphemeral() ? WebCore::ResourceLoadStatistics::IsEphemeral::Yes : WebCore::ResourceLoadStatistics::IsEphemeral::No)); ResourceLoadObserver::shared().setDomainsWithUserInteraction(WTFMove(parameters.domainsWithUserInteraction)); if (!parameters.sessionID.isEphemeral()) ResourceLoadObserver::shared().setDomainsWithCrossPageStorageAccess(WTFMove(parameters.domainsWithStorageAccessQuirk), [] { }); } #endif for (auto& supplement : m_supplements.values()) supplement->setWebsiteDataStore(parameters); platformSetWebsiteDataStoreParameters(WTFMove(parameters)); ensureNetworkProcessConnection(); } bool WebProcess::areAllPagesSuspended() const { for (auto& page : m_pageMap.values()) { if (!page->isSuspended()) return false; } return true; } void WebProcess::setHasSuspendedPageProxy(bool hasSuspendedPageProxy) { ASSERT(m_hasSuspendedPageProxy != hasSuspendedPageProxy); m_hasSuspendedPageProxy = hasSuspendedPageProxy; } void WebProcess::setIsInProcessCache(bool isInProcessCache) { #if PLATFORM(COCOA) if (isInProcessCache) { ASSERT(m_processType == ProcessType::WebContent); m_processType = ProcessType::CachedWebContent; } else { ASSERT(m_processType == ProcessType::CachedWebContent); m_processType = ProcessType::WebContent; } updateProcessName(IsInProcessInitialization::No); IPC::AccessibilityProcessSuspendedNotification(isInProcessCache); #else UNUSED_PARAM(isInProcessCache); #endif } void WebProcess::markIsNoLongerPrewarmed() { #if PLATFORM(COCOA) ASSERT(m_processType == ProcessType::PrewarmedWebContent); m_processType = ProcessType::WebContent; updateProcessName(IsInProcessInitialization::No); #endif } void WebProcess::prewarmGlobally() { if (MemoryPressureHandler::singleton().isUnderMemoryPressure()) { RELEASE_LOG(PerformanceLogging, "WebProcess::prewarmGlobally: Not prewarming because the system in under memory pressure"); return; } WebCore::ProcessWarming::prewarmGlobally(); } void WebProcess::prewarmWithDomainInformation(const WebCore::PrewarmInformation& prewarmInformation) { WebCore::ProcessWarming::prewarmWithInformation(prewarmInformation); } void WebProcess::registerURLSchemeAsEmptyDocument(const String& urlScheme) { LegacySchemeRegistry::registerURLSchemeAsEmptyDocument(urlScheme); } void WebProcess::registerURLSchemeAsSecure(const String& urlScheme) const { LegacySchemeRegistry::registerURLSchemeAsSecure(urlScheme); } void WebProcess::registerURLSchemeAsBypassingContentSecurityPolicy(const String& urlScheme) const { LegacySchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(urlScheme); } void WebProcess::setDomainRelaxationForbiddenForURLScheme(const String& urlScheme) const { LegacySchemeRegistry::setDomainRelaxationForbiddenForURLScheme(true, urlScheme); } void WebProcess::registerURLSchemeAsLocal(const String& urlScheme) const { LegacySchemeRegistry::registerURLSchemeAsLocal(urlScheme); } void WebProcess::registerURLSchemeAsNoAccess(const String& urlScheme) const { LegacySchemeRegistry::registerURLSchemeAsNoAccess(urlScheme); } void WebProcess::registerURLSchemeAsDisplayIsolated(const String& urlScheme) const { LegacySchemeRegistry::registerURLSchemeAsDisplayIsolated(urlScheme); } void WebProcess::registerURLSchemeAsCORSEnabled(const String& urlScheme) { LegacySchemeRegistry::registerURLSchemeAsCORSEnabled(urlScheme); ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::RegisterURLSchemesAsCORSEnabled({ urlScheme }), 0); } void WebProcess::registerURLSchemeAsAlwaysRevalidated(const String& urlScheme) const { LegacySchemeRegistry::registerURLSchemeAsAlwaysRevalidated(urlScheme); } void WebProcess::registerURLSchemeAsCachePartitioned(const String& urlScheme) const { LegacySchemeRegistry::registerURLSchemeAsCachePartitioned(urlScheme); } void WebProcess::registerURLSchemeAsCanDisplayOnlyIfCanRequest(const String& urlScheme) const { LegacySchemeRegistry::registerAsCanDisplayOnlyIfCanRequest(urlScheme); } void WebProcess::setDefaultRequestTimeoutInterval(double timeoutInterval) { ResourceRequest::setDefaultTimeoutInterval(timeoutInterval); } void WebProcess::setAlwaysUsesComplexTextCodePath(bool alwaysUseComplexText) { WebCore::FontCascade::setCodePath(alwaysUseComplexText ? WebCore::FontCascade::CodePath::Complex : WebCore::FontCascade::CodePath::Auto); } void WebProcess::setShouldUseFontSmoothing(bool useFontSmoothing) { WebCore::FontCascade::setShouldUseSmoothing(useFontSmoothing); } void WebProcess::userPreferredLanguagesChanged(const Vector& languages) const { LOG_WITH_STREAM(Language, stream << "The web process's userPreferredLanguagesChanged: " << languages); overrideUserPreferredLanguages(languages); } void WebProcess::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled) { m_fullKeyboardAccessEnabled = fullKeyboardAccessEnabled; } void WebProcess::setCacheModel(CacheModel cacheModel) { if (m_hasSetCacheModel && (cacheModel == m_cacheModel)) return; m_hasSetCacheModel = true; m_cacheModel = cacheModel; unsigned cacheTotalCapacity = 0; unsigned cacheMinDeadCapacity = 0; unsigned cacheMaxDeadCapacity = 0; Seconds deadDecodedDataDeletionInterval; unsigned backForwardCacheSize = 0; calculateMemoryCacheSizes(cacheModel, cacheTotalCapacity, cacheMinDeadCapacity, cacheMaxDeadCapacity, deadDecodedDataDeletionInterval, backForwardCacheSize); auto& memoryCache = MemoryCache::singleton(); memoryCache.setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity); memoryCache.setDeadDecodedDataDeletionInterval(deadDecodedDataDeletionInterval); BackForwardCache::singleton().setMaxSize(backForwardCacheSize); platformSetCacheModel(cacheModel); } WebPage* WebProcess::focusedWebPage() const { for (auto& page : m_pageMap.values()) { if (page->windowAndWebPageAreFocused()) return page.get(); } return 0; } WebPage* WebProcess::webPage(PageIdentifier pageID) const { return m_pageMap.get(pageID); } void WebProcess::createWebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters) { // It is necessary to check for page existence here since during a window.open() (or targeted // link) the WebPage gets created both in the synchronous handler and through the normal way. auto result = m_pageMap.add(pageID, nullptr); if (result.isNewEntry) { ASSERT(!result.iterator->value); auto page = WebPage::create(pageID, WTFMove(parameters)); result.iterator->value = page.ptr(); #if ENABLE(GPU_PROCESS) if (m_gpuProcessConnection) page->gpuProcessConnectionDidBecomeAvailable(*m_gpuProcessConnection); #endif // Balanced by an enableTermination in removeWebPage. disableTermination(); updateCPULimit(); #if OS(LINUX) RealTimeThreads::singleton().setEnabled(hasVisibleWebPage()); #endif } else result.iterator->value->reinitializeWebPage(WTFMove(parameters)); ASSERT(result.iterator->value); } void WebProcess::removeWebPage(PageIdentifier pageID) { ASSERT(m_pageMap.contains(pageID)); flushResourceLoadStatistics(); pageWillLeaveWindow(pageID); m_pageMap.remove(pageID); enableTermination(); updateCPULimit(); #if OS(LINUX) RealTimeThreads::singleton().setEnabled(hasVisibleWebPage()); #endif } bool WebProcess::shouldTerminate() { ASSERT(m_pageMap.isEmpty()); // FIXME: the ShouldTerminate message should also send termination parameters, such as any session cookies that need to be preserved. bool shouldTerminate = false; if (parentProcessConnection()->sendSync(Messages::WebProcessProxy::ShouldTerminate(), Messages::WebProcessProxy::ShouldTerminate::Reply(shouldTerminate), 0) && !shouldTerminate) return false; return true; } void WebProcess::terminate() { #ifndef NDEBUG // These are done in an attempt to reduce LEAK output. GCController::singleton().garbageCollectNow(); FontCache::forCurrentThread().invalidate(); MemoryCache::singleton().setDisabled(true); #endif m_webConnection->invalidate(); m_webConnection = nullptr; platformTerminate(); AuxiliaryProcess::terminate(); } bool WebProcess::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, UniqueRef& replyEncoder) { if (messageReceiverMap().dispatchSyncMessage(connection, decoder, replyEncoder)) return true; return false; } void WebProcess::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder) { if (messageReceiverMap().dispatchMessage(connection, decoder)) return; if (decoder.messageReceiverName() == Messages::WebProcess::messageReceiverName()) { didReceiveWebProcessMessage(connection, decoder); return; } if (decoder.messageReceiverName() == Messages::AuxiliaryProcess::messageReceiverName()) { AuxiliaryProcess::didReceiveMessage(connection, decoder); return; } #if ENABLE(SERVICE_WORKER) // FIXME: Remove? if (decoder.messageReceiverName() == Messages::WebSWContextManagerConnection::messageReceiverName()) { ASSERT(SWContextManager::singleton().connection()); if (auto* contextManagerConnection = SWContextManager::singleton().connection()) static_cast(*contextManagerConnection).didReceiveMessage(connection, decoder); return; } #endif LOG_ERROR("Unhandled web process message '%s' (destination: %" PRIu64 " pid: %d)", description(decoder.messageName()), decoder.destinationID(), static_cast(getCurrentProcessID())); } WebFrame* WebProcess::webFrame(FrameIdentifier frameID) const { return m_frameMap.get(frameID); } Vector WebProcess::webFrames() const { return copyToVector(m_frameMap.values()); } void WebProcess::addWebFrame(FrameIdentifier frameID, WebFrame* frame) { m_frameMap.set(frameID, frame); } void WebProcess::removeWebFrame(FrameIdentifier frameID) { m_frameMap.remove(frameID); // We can end up here after our connection has closed when WebCore's frame life-support timer // fires when the application is shutting down. There's no need (and no way) to update the UI // process in this case. if (!parentProcessConnection()) return; parentProcessConnection()->send(Messages::WebProcessProxy::DidDestroyFrame(frameID), 0); } WebPageGroupProxy* WebProcess::webPageGroup(PageGroup* pageGroup) { for (auto& page : m_pageGroupMap.values()) { if (page->corePageGroup() == pageGroup) return page.get(); } return 0; } WebPageGroupProxy* WebProcess::webPageGroup(PageGroupIdentifier pageGroupID) { return m_pageGroupMap.get(pageGroupID); } WebPageGroupProxy* WebProcess::webPageGroup(const WebPageGroupData& pageGroupData) { auto result = m_pageGroupMap.add(pageGroupData.pageGroupID, nullptr); if (result.isNewEntry) { ASSERT(!result.iterator->value); result.iterator->value = WebPageGroupProxy::create(pageGroupData); } return result.iterator->value.get(); } static uint64_t nextUserGestureTokenIdentifier() { static uint64_t identifier = 1; return identifier++; } uint64_t WebProcess::userGestureTokenIdentifier(RefPtr token) { if (!token || !token->processingUserGesture()) return 0; auto result = m_userGestureTokens.ensure(token.get(), [] { return nextUserGestureTokenIdentifier(); }); if (result.isNewEntry) { result.iterator->key->addDestructionObserver([] (UserGestureToken& tokenBeingDestroyed) { WebProcess::singleton().userGestureTokenDestroyed(tokenBeingDestroyed); }); } return result.iterator->value; } void WebProcess::userGestureTokenDestroyed(UserGestureToken& token) { auto identifier = m_userGestureTokens.take(&token); parentProcessConnection()->send(Messages::WebProcessProxy::DidDestroyUserGestureToken(identifier), 0); } void WebProcess::isJITEnabled(CompletionHandler&& completionHandler) { completionHandler(JSC::Options::useJIT()); } void WebProcess::refreshPlugins() { } void WebProcess::garbageCollectJavaScriptObjects() { GCController::singleton().garbageCollectNow(); } void WebProcess::backgroundResponsivenessPing() { parentProcessConnection()->send(Messages::WebProcessProxy::DidReceiveBackgroundResponsivenessPing(), 0); } void WebProcess::messagesAvailableForPort(const MessagePortIdentifier& identifier) { MessagePort::notifyMessageAvailable(identifier); } #if HAVE(MOUSE_DEVICE_OBSERVATION) void WebProcess::setHasMouseDevice(bool hasMouseDevice) { if (hasMouseDevice == m_hasMouseDevice) return; m_hasMouseDevice = hasMouseDevice; Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment(); } #endif // HAVE(MOUSE_DEVICE_OBSERVATION) #if HAVE(STYLUS_DEVICE_OBSERVATION) void WebProcess::setHasStylusDevice(bool hasStylusDevice) { if (hasStylusDevice == m_hasStylusDevice) return; m_hasStylusDevice = hasStylusDevice; Page::updateStyleForAllPagesAfterGlobalChangeInEnvironment(); } #endif // HAVE(STYLUS_DEVICE_OBSERVATION) #if ENABLE(GAMEPAD) void WebProcess::setInitialGamepads(const Vector& gamepadDatas) { WebGamepadProvider::singleton().setInitialGamepads(gamepadDatas); } void WebProcess::gamepadConnected(const GamepadData& gamepadData, WebCore::EventMakesGamepadsVisible eventVisibility) { WebGamepadProvider::singleton().gamepadConnected(gamepadData, eventVisibility); } void WebProcess::gamepadDisconnected(unsigned index) { WebGamepadProvider::singleton().gamepadDisconnected(index); } #endif void WebProcess::setJavaScriptGarbageCollectorTimerEnabled(bool flag) { GCController::singleton().setJavaScriptGarbageCollectorTimerEnabled(flag); } void WebProcess::handleInjectedBundleMessage(const String& messageName, const UserData& messageBody) { InjectedBundle* injectedBundle = WebProcess::singleton().injectedBundle(); if (!injectedBundle) return; injectedBundle->didReceiveMessage(messageName, transformHandlesToObjects(messageBody.object()).get()); } void WebProcess::setInjectedBundleParameter(const String& key, const IPC::DataReference& value) { InjectedBundle* injectedBundle = WebProcess::singleton().injectedBundle(); if (!injectedBundle) return; injectedBundle->setBundleParameter(key, value); } void WebProcess::setInjectedBundleParameters(const IPC::DataReference& value) { InjectedBundle* injectedBundle = WebProcess::singleton().injectedBundle(); if (!injectedBundle) return; injectedBundle->setBundleParameters(value); } static NetworkProcessConnectionInfo getNetworkProcessConnection(IPC::Connection& connection) { NetworkProcessConnectionInfo connectionInfo; auto requestConnection = [&] { if (!connection.isValid()) { // Connection to UIProcess has been severed, exit cleanly. exit(0); } if (!connection.sendSync(Messages::WebProcessProxy::GetNetworkProcessConnection(), Messages::WebProcessProxy::GetNetworkProcessConnection::Reply(connectionInfo), 0)) { RELEASE_LOG_ERROR(Process, "getNetworkProcessConnection: Failed to send or receive message"); return false; } return IPC::Connection::identifierIsValid(connectionInfo.identifier()); }; static constexpr unsigned maxFailedAttempts = 10; unsigned failedAttempts = 0; while (!requestConnection()) { if (++failedAttempts >= maxFailedAttempts) CRASH(); RELEASE_LOG_ERROR(Process, "getNetworkProcessConnection: Failed to get connection to network process, will retry..."); // If we failed, retry after a delay. The attachment may have become invalid // before it was received by the web process if the network process crashed. sleep(100_ms); } return connectionInfo; } NetworkProcessConnection& WebProcess::ensureNetworkProcessConnection() { RELEASE_ASSERT(RunLoop::isMain()); ASSERT(m_sessionID); // If we've lost our connection to the network process (e.g. it crashed) try to re-establish it. if (!m_networkProcessConnection) { auto connectionInfo = getNetworkProcessConnection(*parentProcessConnection()); m_networkProcessConnection = NetworkProcessConnection::create(connectionInfo.releaseIdentifier(), connectionInfo.cookieAcceptPolicy); #if HAVE(AUDIT_TOKEN) m_networkProcessConnection->setNetworkProcessAuditToken(WTFMove(connectionInfo.auditToken)); #endif m_networkProcessConnection->connection().send(Messages::NetworkConnectionToWebProcess::RegisterURLSchemesAsCORSEnabled(WebCore::LegacySchemeRegistry::allURLSchemesRegisteredAsCORSEnabled()), 0); #if ENABLE(SERVICE_WORKER) if (!Document::allDocuments().isEmpty()) m_networkProcessConnection->serviceWorkerConnection().registerServiceWorkerClients(); #endif // This can be called during a WebPage's constructor, so wait until after the constructor returns to touch the WebPage. RunLoop::main().dispatch([this] { for (auto& webPage : m_pageMap.values()) webPage->synchronizeCORSDisablingPatternsWithNetworkProcess(); }); } return *m_networkProcessConnection; } void WebProcess::logDiagnosticMessageForNetworkProcessCrash() { WebCore::Page* page = nullptr; if (auto* webPage = focusedWebPage()) page = webPage->corePage(); if (!page) { for (auto& webPage : m_pageMap.values()) { if (auto* corePage = webPage->corePage()) { page = corePage; break; } } } if (page) page->diagnosticLoggingClient().logDiagnosticMessage(WebCore::DiagnosticLoggingKeys::internalErrorKey(), WebCore::DiagnosticLoggingKeys::networkProcessCrashedKey(), WebCore::ShouldSample::No); } void WebProcess::networkProcessConnectionClosed(NetworkProcessConnection* connection) { #if OS(DARWIN) WEBPROCESS_RELEASE_LOG(Loading, "networkProcessConnectionClosed: NetworkProcess (%d) closed its connection (Crashed)", connection ? connection->connection().remoteProcessID() : 0); #else WEBPROCESS_RELEASE_LOG(Loading, "networkProcessConnectionClosed: NetworkProcess closed its connection (Crashed)"); #endif ASSERT(m_networkProcessConnection); ASSERT_UNUSED(connection, m_networkProcessConnection == connection); for (auto key : copyToVector(m_storageAreaMaps.keys())) { if (auto map = m_storageAreaMaps.get(key)) map->disconnect(); } for (auto& page : m_pageMap.values()) { auto idbConnection = page->corePage()->optionalIDBConnection(); if (!idbConnection) continue; if (auto* existingIDBConnectionToServer = connection->existingIDBConnectionToServer()) { ASSERT_UNUSED(existingIDBConnectionToServer, idbConnection == &existingIDBConnectionToServer->coreConnectionToServer()); page->corePage()->clearIDBConnection(); } } #if ENABLE(SERVICE_WORKER) if (SWContextManager::singleton().connection()) SWContextManager::singleton().stopAllServiceWorkers(); #endif m_networkProcessConnection = nullptr; logDiagnosticMessageForNetworkProcessCrash(); m_webLoaderStrategy.networkProcessCrashed(); WebSocketStream::networkProcessCrashed(); m_webSocketChannelManager.networkProcessCrashed(); m_broadcastChannelRegistry->networkProcessCrashed(); if (m_libWebRTCNetwork) m_libWebRTCNetwork->networkProcessCrashed(); for (auto& page : m_pageMap.values()) { page->stopAllURLSchemeTasks(); #if ENABLE(APPLE_PAY) if (auto paymentCoordinator = page->paymentCoordinator()) paymentCoordinator->networkProcessConnectionClosed(); #endif } // Recreate a new connection with valid IPC connection on next operation. if (m_fileSystemStorageConnection) { m_fileSystemStorageConnection->connectionClosed(); m_fileSystemStorageConnection = nullptr; } } WebFileSystemStorageConnection& WebProcess::fileSystemStorageConnection() { if (!m_fileSystemStorageConnection) m_fileSystemStorageConnection = WebFileSystemStorageConnection::create(ensureNetworkProcessConnection().connection()); return *m_fileSystemStorageConnection; } WebLoaderStrategy& WebProcess::webLoaderStrategy() { return m_webLoaderStrategy; } #if ENABLE(GPU_PROCESS) #if !PLATFORM(COCOA) void WebProcess::platformInitializeGPUProcessConnectionParameters(GPUProcessConnectionParameters&) { } #endif GPUProcessConnectionInfo WebProcess::getGPUProcessConnection(IPC::Connection& connection) { GPUProcessConnectionParameters parameters; platformInitializeGPUProcessConnectionParameters(parameters); IPC::UnboundedSynchronousIPCScope unboundedSynchronousIPCScope; GPUProcessConnectionInfo connectionInfo; if (!connection.sendSync(Messages::WebProcessProxy::GetGPUProcessConnection(parameters), Messages::WebProcessProxy::GetGPUProcessConnection::Reply(connectionInfo), 0)) { // If we failed the first time, retry once. The attachment may have become invalid // before it was received by the web process if the network process crashed. if (!connection.sendSync(Messages::WebProcessProxy::GetGPUProcessConnection(parameters), Messages::WebProcessProxy::GetGPUProcessConnection::Reply(connectionInfo), 0)) CRASH(); } return connectionInfo; } GPUProcessConnection& WebProcess::ensureGPUProcessConnection() { RELEASE_ASSERT(RunLoop::isMain()); // If we've lost our connection to the GPU process (e.g. it crashed) try to re-establish it. if (!m_gpuProcessConnection) { auto connectionInfo = getGPUProcessConnection(*parentProcessConnection()); // Retry once if the IPC to get the connectionIdentifier succeeded but the connectionIdentifier we received // is invalid. This may indicate that the GPU process has crashed. if (!IPC::Connection::identifierIsValid(connectionInfo.identifier())) connectionInfo = getGPUProcessConnection(*parentProcessConnection()); if (!IPC::Connection::identifierIsValid(connectionInfo.identifier())) CRASH(); m_gpuProcessConnection = GPUProcessConnection::create(connectionInfo.releaseIdentifier(), connectionInfo.parameters); #if HAVE(AUDIT_TOKEN) ASSERT(connectionInfo.auditToken); m_gpuProcessConnection->setAuditToken(WTFMove(connectionInfo.auditToken)); #endif #if ENABLE(IPC_TESTING_API) if (parentProcessConnection()->ignoreInvalidMessageForTesting()) m_gpuProcessConnection->connection().setIgnoreInvalidMessageForTesting(); #endif for (auto& page : m_pageMap.values()) { // If page is null, then it is currently being constructed. if (page) page->gpuProcessConnectionDidBecomeAvailable(*m_gpuProcessConnection); } } return *m_gpuProcessConnection; } void WebProcess::gpuProcessConnectionClosed(GPUProcessConnection& connection) { ASSERT(m_gpuProcessConnection); ASSERT_UNUSED(connection, m_gpuProcessConnection == &connection); m_gpuProcessConnection = nullptr; #if ENABLE(MEDIA_STREAM) && PLATFORM(COCOA) if (m_audioMediaStreamTrackRendererInternalUnitManager) m_audioMediaStreamTrackRendererInternalUnitManager->restartAllUnits(); #endif } #if PLATFORM(COCOA) && USE(LIBWEBRTC) LibWebRTCCodecs& WebProcess::libWebRTCCodecs() { if (!m_libWebRTCCodecs) m_libWebRTCCodecs = LibWebRTCCodecs::create(); return *m_libWebRTCCodecs; } #endif #if ENABLE(MEDIA_STREAM) && PLATFORM(COCOA) AudioMediaStreamTrackRendererInternalUnitManager& WebProcess::audioMediaStreamTrackRendererInternalUnitManager() { if (!m_audioMediaStreamTrackRendererInternalUnitManager) m_audioMediaStreamTrackRendererInternalUnitManager = makeUnique(); return *m_audioMediaStreamTrackRendererInternalUnitManager; } #endif #endif // ENABLE(GPU_PROCESS) #if ENABLE(WEB_AUTHN) static WebAuthnProcessConnectionInfo getWebAuthnProcessConnection(IPC::Connection& connection) { WebAuthnProcessConnectionInfo connectionInfo; if (!connection.sendSync(Messages::WebProcessProxy::GetWebAuthnProcessConnection(), Messages::WebProcessProxy::GetWebAuthnProcessConnection::Reply(connectionInfo), 0)) { // If we failed the first time, retry once. The attachment may have become invalid // before it was received by the web process if the network process crashed. if (!connection.sendSync(Messages::WebProcessProxy::GetWebAuthnProcessConnection(), Messages::WebProcessProxy::GetWebAuthnProcessConnection::Reply(connectionInfo), 0)) { RELEASE_LOG_ERROR(WebAuthn, "getWebAuthnProcessConnection: Unable to connect to WebAuthn process (Terminating)"); CRASH(); } } return connectionInfo; } WebAuthnProcessConnection& WebProcess::ensureWebAuthnProcessConnection() { RELEASE_ASSERT(RunLoop::isMain()); // If we've lost our connection to the WebAuthn process (e.g. it crashed) try to re-establish it. if (!m_webAuthnProcessConnection) { auto connectionInfo = getWebAuthnProcessConnection(*parentProcessConnection()); // Retry once if the IPC to get the connectionIdentifier succeeded but the connectionIdentifier we received // is invalid. This may indicate that the WebAuthn process has crashed. if (!IPC::Connection::identifierIsValid(connectionInfo.identifier())) connectionInfo = getWebAuthnProcessConnection(*parentProcessConnection()); if (!IPC::Connection::identifierIsValid(connectionInfo.identifier())) { RELEASE_LOG_ERROR(WebAuthn, "ensureWebAuthnProcessConnection: Connection identifier for WebAuthn process is invalid."); CRASH(); } m_webAuthnProcessConnection = WebAuthnProcessConnection::create(connectionInfo.releaseIdentifier()); } return *m_webAuthnProcessConnection; } void WebProcess::webAuthnProcessConnectionClosed(WebAuthnProcessConnection* connection) { ASSERT(m_webAuthnProcessConnection); ASSERT_UNUSED(connection, m_webAuthnProcessConnection == connection); m_webAuthnProcessConnection = nullptr; } #endif // ENABLE(WEB_AUTHN) void WebProcess::setEnhancedAccessibility(bool flag) { WebCore::AXObjectCache::setEnhancedUserInterfaceAccessibility(flag); } void WebProcess::startMemorySampler(SandboxExtension::Handle&& sampleLogFileHandle, const String& sampleLogFilePath, const double interval) { #if ENABLE(MEMORY_SAMPLER) WebMemorySampler::singleton()->start(WTFMove(sampleLogFileHandle), sampleLogFilePath, interval); #else UNUSED_PARAM(sampleLogFileHandle); UNUSED_PARAM(sampleLogFilePath); UNUSED_PARAM(interval); #endif } void WebProcess::stopMemorySampler() { #if ENABLE(MEMORY_SAMPLER) WebMemorySampler::singleton()->stop(); #endif } void WebProcess::setTextCheckerState(const TextCheckerState& textCheckerState) { bool continuousSpellCheckingTurnedOff = !textCheckerState.isContinuousSpellCheckingEnabled && m_textCheckerState.isContinuousSpellCheckingEnabled; bool grammarCheckingTurnedOff = !textCheckerState.isGrammarCheckingEnabled && m_textCheckerState.isGrammarCheckingEnabled; m_textCheckerState = textCheckerState; if (!continuousSpellCheckingTurnedOff && !grammarCheckingTurnedOff) return; for (auto& page : m_pageMap.values()) { if (continuousSpellCheckingTurnedOff) page->unmarkAllMisspellings(); if (grammarCheckingTurnedOff) page->unmarkAllBadGrammar(); } } void WebProcess::fetchWebsiteData(OptionSet websiteDataTypes, CompletionHandler&& completionHandler) { WebsiteData websiteData; if (websiteDataTypes.contains(WebsiteDataType::MemoryCache)) { for (auto& origin : MemoryCache::singleton().originsWithCache(sessionID())) websiteData.entries.append(WebsiteData::Entry { origin->data(), WebsiteDataType::MemoryCache, 0 }); } completionHandler(WTFMove(websiteData)); } void WebProcess::deleteWebsiteData(OptionSet websiteDataTypes, WallTime modifiedSince, CompletionHandler&& completionHandler) { UNUSED_PARAM(modifiedSince); if (websiteDataTypes.contains(WebsiteDataType::MemoryCache)) { BackForwardCache::singleton().pruneToSizeNow(0, PruningReason::None); MemoryCache::singleton().evictResources(sessionID()); CrossOriginPreflightResultCache::singleton().clear(); } completionHandler(); } void WebProcess::deleteWebsiteDataForOrigins(OptionSet websiteDataTypes, const Vector& originDatas, CompletionHandler&& completionHandler) { if (websiteDataTypes.contains(WebsiteDataType::MemoryCache)) { HashSet> origins; for (auto& originData : originDatas) origins.add(originData.securityOrigin()); MemoryCache::singleton().removeResourcesWithOrigins(sessionID(), origins); } completionHandler(); } void WebProcess::setHiddenPageDOMTimerThrottlingIncreaseLimit(int milliseconds) { for (auto& page : m_pageMap.values()) page->setHiddenPageDOMTimerThrottlingIncreaseLimit(Seconds::fromMilliseconds(milliseconds)); } #if !PLATFORM(COCOA) void WebProcess::initializeProcessName(const AuxiliaryProcessInitializationParameters&) { } void WebProcess::initializeSandbox(const AuxiliaryProcessInitializationParameters&, SandboxInitializationParameters&) { } void WebProcess::updateActivePages(const String& overrideDisplayName) { } void WebProcess::getActivePagesOriginsForTesting(CompletionHandler&&)>&& completionHandler) { completionHandler({ }); } void WebProcess::updateCPULimit() { } void WebProcess::updateCPUMonitorState(CPUMonitorUpdateReason) { } #endif void WebProcess::pageActivityStateDidChange(PageIdentifier, OptionSet changed) { if (changed & WebCore::ActivityState::IsVisible) { updateCPUMonitorState(CPUMonitorUpdateReason::VisibilityHasChanged); #if OS(LINUX) RealTimeThreads::singleton().setEnabled(hasVisibleWebPage()); #endif } } #if PLATFORM(IOS_FAMILY) void WebProcess::resetAllGeolocationPermissions() { for (auto& page : m_pageMap.values()) { if (Frame* mainFrame = page->mainFrame()) mainFrame->resetAllGeolocationPermission(); } } #endif void WebProcess::prepareToSuspend(bool isSuspensionImminent, CompletionHandler&& completionHandler) { WEBPROCESS_RELEASE_LOG(ProcessSuspension, "prepareToSuspend: isSuspensionImminent=%d", isSuspensionImminent); SetForScope suspensionScope(m_isSuspending, true); m_processIsSuspended = true; flushResourceLoadStatistics(); #if PLATFORM(COCOA) if (m_processType == ProcessType::PrewarmedWebContent) { WEBPROCESS_RELEASE_LOG(ProcessSuspension, "prepareToSuspend: Process is ready to suspend"); return completionHandler(); } #endif #if ENABLE(VIDEO) suspendAllMediaBuffering(); if (auto* platformMediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists()) platformMediaSessionManager->processWillSuspend(); #endif if (!m_suppressMemoryPressureHandler) { MemoryPressureHandler::singleton().releaseMemory(Critical::Yes, Synchronous::Yes); for (auto& page : m_pageMap.values()) page->releaseMemory(Critical::Yes); } freezeAllLayerTrees(); #if PLATFORM(COCOA) destroyRenderingResources(); #endif #if PLATFORM(IOS_FAMILY) m_webSQLiteDatabaseTracker.setIsSuspended(true); SQLiteDatabase::setIsDatabaseOpeningForbidden(true); if (DatabaseTracker::isInitialized()) DatabaseTracker::singleton().closeAllDatabases(CurrentQueryBehavior::Interrupt); IPC::AccessibilityProcessSuspendedNotification(true); updateFreezerStatus(); #endif markAllLayersVolatile([this, completionHandler = WTFMove(completionHandler)]() mutable { WEBPROCESS_RELEASE_LOG(ProcessSuspension, "prepareToSuspend: Process is ready to suspend"); completionHandler(); }); } void WebProcess::markAllLayersVolatile(CompletionHandler&& completionHandler) { WEBPROCESS_RELEASE_LOG(ProcessSuspension, "markAllLayersVolatile:"); auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler)); for (auto& page : m_pageMap.values()) { page->markLayersVolatile([this, callbackAggregator, pageID = page->identifier()] (bool succeeded) { if (succeeded) WEBPROCESS_RELEASE_LOG(ProcessSuspension, "markAllLayersVolatile: Successfuly marked layers as volatile for webPageID=%" PRIu64, pageID.toUInt64()); else WEBPROCESS_RELEASE_LOG_ERROR(ProcessSuspension, "markAllLayersVolatile: Failed to mark layers as volatile for webPageID=%" PRIu64, pageID.toUInt64()); }); } } void WebProcess::cancelMarkAllLayersVolatile() { WEBPROCESS_RELEASE_LOG(ProcessSuspension, "cancelMarkAllLayersVolatile:"); for (auto& page : m_pageMap.values()) page->cancelMarkLayersVolatile(); } void WebProcess::freezeAllLayerTrees() { WEBPROCESS_RELEASE_LOG(ProcessSuspension, "freezeAllLayerTrees: WebProcess is freezing all layer trees"); for (auto& page : m_pageMap.values()) page->freezeLayerTree(WebPage::LayerTreeFreezeReason::ProcessSuspended); } void WebProcess::unfreezeAllLayerTrees() { WEBPROCESS_RELEASE_LOG(ProcessSuspension, "unfreezeAllLayerTrees: WebProcess is unfreezing all layer trees"); for (auto& page : m_pageMap.values()) page->unfreezeLayerTree(WebPage::LayerTreeFreezeReason::ProcessSuspended); } void WebProcess::processDidResume() { WEBPROCESS_RELEASE_LOG(ProcessSuspension, "processDidResume:"); m_processIsSuspended = false; #if PLATFORM(COCOA) if (m_processType == ProcessType::PrewarmedWebContent) return; #endif cancelMarkAllLayersVolatile(); unfreezeAllLayerTrees(); #if PLATFORM(IOS_FAMILY) m_webSQLiteDatabaseTracker.setIsSuspended(false); SQLiteDatabase::setIsDatabaseOpeningForbidden(false); IPC::AccessibilityProcessSuspendedNotification(false); #endif #if ENABLE(VIDEO) if (auto* platformMediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists()) platformMediaSessionManager->processDidResume(); resumeAllMediaBuffering(); #endif } void WebProcess::sendPrewarmInformation(const URL& url) { auto registrableDomain = WebCore::RegistrableDomain { url }; if (registrableDomain.isEmpty()) return; parentProcessConnection()->send(Messages::WebProcessProxy::DidCollectPrewarmInformation(registrableDomain, WebCore::ProcessWarming::collectPrewarmInformation()), 0); } void WebProcess::pageDidEnterWindow(PageIdentifier pageID) { m_pagesInWindows.add(pageID); m_nonVisibleProcessGraphicsCleanupTimer.stop(); #if ENABLE(NON_VISIBLE_WEBPROCESS_MEMORY_CLEANUP_TIMER) m_nonVisibleProcessMemoryCleanupTimer.stop(); #endif } void WebProcess::pageWillLeaveWindow(PageIdentifier pageID) { m_pagesInWindows.remove(pageID); if (m_pagesInWindows.isEmpty()) { if (!m_nonVisibleProcessGraphicsCleanupTimer.isActive()) m_nonVisibleProcessGraphicsCleanupTimer.startOneShot(nonVisibleProcessGraphicsCleanupDelay); #if ENABLE(NON_VISIBLE_WEBPROCESS_MEMORY_CLEANUP_TIMER) if (!m_nonVisibleProcessMemoryCleanupTimer.isActive()) m_nonVisibleProcessMemoryCleanupTimer.startOneShot(nonVisibleProcessMemoryCleanupDelay); #endif } } void WebProcess::nonVisibleProcessGraphicsCleanupTimerFired() { ASSERT(m_pagesInWindows.isEmpty()); if (!m_pagesInWindows.isEmpty()) return; #if PLATFORM(COCOA) destroyRenderingResources(); #endif } #if ENABLE(NON_VISIBLE_WEBPROCESS_MEMORY_CLEANUP_TIMER) void WebProcess::nonVisibleProcessMemoryCleanupTimerFired() { ASSERT(m_pagesInWindows.isEmpty()); if (!m_pagesInWindows.isEmpty()) return; // If this is a process that we keep around for performance, then don't proactively slim it down until absolutely necessary (in the memory pressure handler). if (m_processType == ProcessType::CachedWebContent || areAllPagesSuspended()) return; WebCore::releaseMemory(Critical::Yes, Synchronous::No, MaintainBackForwardCache::Yes, MaintainMemoryCache::No); for (auto& page : m_pageMap.values()) page->releaseMemory(Critical::Yes); } #endif void WebProcess::registerStorageAreaMap(StorageAreaMap& storageAreaMap) { auto identifier = storageAreaMap.identifier(); ASSERT(!m_storageAreaMaps.contains(identifier)); m_storageAreaMaps.add(identifier, storageAreaMap); } void WebProcess::unregisterStorageAreaMap(StorageAreaMap& storageAreaMap) { auto identifier = storageAreaMap.identifier(); ASSERT(m_storageAreaMaps.contains(identifier)); ASSERT(m_storageAreaMaps.get(identifier).get() == &storageAreaMap); m_storageAreaMaps.remove(identifier); } WeakPtr WebProcess::storageAreaMap(StorageAreaMapIdentifier identifier) const { return m_storageAreaMaps.get(identifier); } void WebProcess::setResourceLoadStatisticsEnabled(bool enabled) { if (WebCore::DeprecatedGlobalSettings::resourceLoadStatisticsEnabled() == enabled) return; WebCore::DeprecatedGlobalSettings::setResourceLoadStatisticsEnabled(enabled); #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) if (enabled && !ResourceLoadObserver::sharedIfExists()) WebCore::ResourceLoadObserver::setShared(*new WebResourceLoadObserver(m_sessionID && m_sessionID->isEphemeral() ? WebCore::ResourceLoadStatistics::IsEphemeral::Yes : WebCore::ResourceLoadStatistics::IsEphemeral::No)); #endif } void WebProcess::clearResourceLoadStatistics() { #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) if (auto* observer = ResourceLoadObserver::sharedIfExists()) observer->clearState(); for (auto& page : m_pageMap.values()) page->clearPageLevelStorageAccess(); #endif } void WebProcess::flushResourceLoadStatistics() { #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) if (auto* observer = ResourceLoadObserver::sharedIfExists()) observer->updateCentralStatisticsStore([] { }); #endif } void WebProcess::seedResourceLoadStatisticsForTesting(const RegistrableDomain& firstPartyDomain, const RegistrableDomain& thirdPartyDomain, bool shouldScheduleNotification, CompletionHandler&& completionHandler) { #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) if (auto* observer = ResourceLoadObserver::sharedIfExists()) observer->logSubresourceLoadingForTesting(firstPartyDomain, thirdPartyDomain, shouldScheduleNotification); #endif completionHandler(); } RefPtr WebProcess::transformHandlesToObjects(API::Object* object) { struct Transformer final : UserData::Transformer { Transformer(WebProcess& webProcess) : m_webProcess(webProcess) { } bool shouldTransformObject(const API::Object& object) const override { switch (object.type()) { case API::Object::Type::FrameHandle: return static_cast(object).isAutoconverting(); case API::Object::Type::PageHandle: return static_cast(object).isAutoconverting(); #if PLATFORM(COCOA) case API::Object::Type::ObjCObjectGraph: #endif return true; default: return false; } } RefPtr transformObject(API::Object& object) const override { switch (object.type()) { case API::Object::Type::FrameHandle: return m_webProcess.webFrame(static_cast(object).frameID()); case API::Object::Type::PageHandle: return m_webProcess.webPage(static_cast(object).webPageID()); #if PLATFORM(COCOA) case API::Object::Type::ObjCObjectGraph: return m_webProcess.transformHandlesToObjects(static_cast(object)); #endif default: return &object; } } WebProcess& m_webProcess; }; return UserData::transform(object, Transformer(*this)); } RefPtr WebProcess::transformObjectsToHandles(API::Object* object) { struct Transformer final : UserData::Transformer { bool shouldTransformObject(const API::Object& object) const override { switch (object.type()) { case API::Object::Type::BundleFrame: case API::Object::Type::BundlePage: #if PLATFORM(COCOA) case API::Object::Type::ObjCObjectGraph: #endif return true; default: return false; } } RefPtr transformObject(API::Object& object) const override { switch (object.type()) { case API::Object::Type::BundleFrame: return API::FrameHandle::createAutoconverting(static_cast(object).frameID()); case API::Object::Type::BundlePage: return API::PageHandle::createAutoconverting(static_cast(object).webPageProxyIdentifier(), static_cast(object).identifier()); #if PLATFORM(COCOA) case API::Object::Type::ObjCObjectGraph: return transformObjectsToHandles(static_cast(object)); #endif default: return &object; } } }; return UserData::transform(object, Transformer()); } void WebProcess::setMemoryCacheDisabled(bool disabled) { auto& memoryCache = MemoryCache::singleton(); if (memoryCache.disabled() != disabled) memoryCache.setDisabled(disabled); } #if ENABLE(SERVICE_CONTROLS) void WebProcess::setEnabledServices(bool hasImageServices, bool hasSelectionServices, bool hasRichContentServices) { m_hasImageServices = hasImageServices; m_hasSelectionServices = hasSelectionServices; m_hasRichContentServices = hasRichContentServices; } #endif void WebProcess::ensureAutomationSessionProxy(const String& sessionIdentifier) { m_automationSessionProxy = makeUnique(sessionIdentifier); } void WebProcess::destroyAutomationSessionProxy() { m_automationSessionProxy = nullptr; } void WebProcess::prefetchDNS(const String& hostname) { if (hostname.isEmpty()) return; if (m_dnsPrefetchedHosts.add(hostname).isNewEntry) ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::PrefetchDNS(hostname), 0); // The DNS prefetched hosts cache is only to avoid asking for the same hosts too many times // in a very short period of time, producing a lot of IPC traffic. So we clear this cache after // some time of no DNS requests. m_dnsPrefetchHystereris.impulse(); } bool WebProcess::hasVisibleWebPage() const { for (auto& page : m_pageMap.values()) { if (page->isVisible()) return true; } return false; } void WebProcess::setBackForwardCacheCapacity(unsigned capacity) { BackForwardCache::singleton().setMaxSize(capacity); } void WebProcess::clearCachedPage(BackForwardItemIdentifier backForwardItemID, CompletionHandler&& completionHandler) { HistoryItem* item = WebBackForwardListProxy::itemForID(backForwardItemID); if (!item) return completionHandler(); BackForwardCache::singleton().remove(*item); completionHandler(); } LibWebRTCNetwork& WebProcess::libWebRTCNetwork() { if (!m_libWebRTCNetwork) m_libWebRTCNetwork = LibWebRTCNetwork::create(); return *m_libWebRTCNetwork; } #if ENABLE(SERVICE_WORKER) void WebProcess::establishWorkerContextConnectionToNetworkProcess(PageGroupIdentifier pageGroupID, WebPageProxyIdentifier webPageProxyID, PageIdentifier pageID, const WebPreferencesStore& store, RegistrableDomain&& registrableDomain, std::optional serviceWorkerPageIdentifier, ServiceWorkerInitializationData&& initializationData, CompletionHandler&& completionHandler) { // We are in the Service Worker context process and the call below establishes our connection to the Network Process // by calling ensureNetworkProcessConnection. SWContextManager needs to use the same underlying IPC::Connection as the // NetworkProcessConnection for synchronization purposes. auto& ipcConnection = ensureNetworkProcessConnection().connection(); SWContextManager::singleton().setConnection(makeUnique(ipcConnection, WTFMove(registrableDomain), serviceWorkerPageIdentifier, pageGroupID, webPageProxyID, pageID, store, WTFMove(initializationData))); SWContextManager::singleton().connection()->establishConnection(WTFMove(completionHandler)); } void WebProcess::addServiceWorkerRegistration(WebCore::ServiceWorkerRegistrationIdentifier identifier) { m_swRegistrationCounts.add(identifier); } bool WebProcess::removeServiceWorkerRegistration(WebCore::ServiceWorkerRegistrationIdentifier identifier) { ASSERT(m_swRegistrationCounts.contains(identifier)); return m_swRegistrationCounts.remove(identifier); } #endif #if ENABLE(MEDIA_STREAM) void WebProcess::addMockMediaDevice(const WebCore::MockMediaDevice& device) { MockRealtimeMediaSourceCenter::addDevice(device); } void WebProcess::clearMockMediaDevices() { MockRealtimeMediaSourceCenter::setDevices({ }); } void WebProcess::removeMockMediaDevice(const String& persistentId) { MockRealtimeMediaSourceCenter::removeDevice(persistentId); } void WebProcess::resetMockMediaDevices() { MockRealtimeMediaSourceCenter::resetDevices(); } #if ENABLE(SANDBOX_EXTENSIONS) void WebProcess::grantUserMediaDeviceSandboxExtensions(MediaDeviceSandboxExtensions&& extensions) { for (size_t i = 0; i < extensions.size(); i++) { const auto& extension = extensions[i]; extension.second->consume(); WEBPROCESS_RELEASE_LOG(WebRTC, "grantUserMediaDeviceSandboxExtensions: granted extension %s", extension.first.utf8().data()); m_mediaCaptureSandboxExtensions.add(extension.first, extension.second.copyRef()); } } static inline void checkDocumentsCaptureStateConsistency(const Vector& extensionIDs) { #if ASSERT_ENABLED bool isCapturingAudio = WTF::anyOf(Document::allDocumentsMap().values(), [](auto* document) { return document->mediaState() & MediaProducer::AudioCaptureMask; }); bool isCapturingVideo = WTF::anyOf(Document::allDocumentsMap().values(), [](auto* document) { return document->mediaState() & MediaProducer::VideoCaptureMask; }); if (isCapturingAudio) ASSERT(extensionIDs.findIf([](auto& id) { return id.contains("microphone"); }) == notFound); if (isCapturingVideo) ASSERT(extensionIDs.findIf([](auto& id) { return id.contains("camera"); }) == notFound); #endif // ASSERT_ENABLED } void WebProcess::revokeUserMediaDeviceSandboxExtensions(const Vector& extensionIDs) { checkDocumentsCaptureStateConsistency(extensionIDs); for (const auto& extensionID : extensionIDs) { auto extension = m_mediaCaptureSandboxExtensions.take(extensionID); ASSERT(extension || MockRealtimeMediaSourceCenter::mockRealtimeMediaSourceCenterEnabled()); if (extension) { extension->revoke(); WEBPROCESS_RELEASE_LOG(WebRTC, "revokeUserMediaDeviceSandboxExtensions: revoked extension %s", extensionID.utf8().data()); } } } #endif #endif #if ENABLE(VIDEO) void WebProcess::suspendAllMediaBuffering() { for (auto& page : m_pageMap.values()) page->suspendAllMediaBuffering(); } void WebProcess::resumeAllMediaBuffering() { for (auto& page : m_pageMap.values()) page->resumeAllMediaBuffering(); } #endif void WebProcess::clearCurrentModifierStateForTesting() { PlatformKeyboardEvent::setCurrentModifierState({ }); } bool WebProcess::areAllPagesThrottleable() const { return WTF::allOf(m_pageMap.values(), [](auto& page) { return page->isThrottleable(); }); } #if HAVE(CVDISPLAYLINK) void WebProcess::displayWasRefreshed(uint32_t displayID, const DisplayUpdate& displayUpdate) { ASSERT(RunLoop::isMain()); m_eventDispatcher->notifyScrollingTreesDisplayWasRefreshed(displayID); DisplayRefreshMonitorManager::sharedManager().displayWasUpdated(displayID, displayUpdate); } #endif #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) void WebProcess::setThirdPartyCookieBlockingMode(ThirdPartyCookieBlockingMode thirdPartyCookieBlockingMode, CompletionHandler&& completionHandler) { m_thirdPartyCookieBlockingMode = thirdPartyCookieBlockingMode; completionHandler(); } void WebProcess::setDomainsWithUserInteraction(HashSet&& domains) { ResourceLoadObserver::shared().setDomainsWithUserInteraction(WTFMove(domains)); } void WebProcess::setDomainsWithCrossPageStorageAccess(HashMap&& domains, CompletionHandler&& completionHandler) { for (auto& domain : domains.keys()) { for (auto& webPage : m_pageMap.values()) webPage->addDomainWithPageLevelStorageAccess(domain, domains.get(domain)); } ResourceLoadObserver::shared().setDomainsWithCrossPageStorageAccess(WTFMove(domains), WTFMove(completionHandler)); } void WebProcess::sendResourceLoadStatisticsDataImmediately(CompletionHandler&& completionHandler) { ResourceLoadObserver::shared().updateCentralStatisticsStore(WTFMove(completionHandler)); } #endif #if ENABLE(GPU_PROCESS) void WebProcess::setUseGPUProcessForCanvasRendering(bool useGPUProcessForCanvasRendering) { m_useGPUProcessForCanvasRendering = useGPUProcessForCanvasRendering; } void WebProcess::setUseGPUProcessForDOMRendering(bool useGPUProcessForDOMRendering) { m_useGPUProcessForDOMRendering = useGPUProcessForDOMRendering; } void WebProcess::setUseGPUProcessForMedia(bool useGPUProcessForMedia) { if (useGPUProcessForMedia == m_useGPUProcessForMedia) return; m_useGPUProcessForMedia = useGPUProcessForMedia; #if ENABLE(ENCRYPTED_MEDIA) auto& cdmFactories = CDMFactory::registeredFactories(); cdmFactories.clear(); if (useGPUProcessForMedia) cdmFactory().registerFactory(cdmFactories); else CDMFactory::platformRegisterFactories(cdmFactories); #endif #if USE(AUDIO_SESSION) if (useGPUProcessForMedia) AudioSession::setSharedSession(RemoteAudioSession::create(*this)); else AudioSession::setSharedSession(AudioSession::create()); #endif #if PLATFORM(IOS_FAMILY) if (useGPUProcessForMedia) MediaSessionHelper::setSharedHelper(makeUniqueRef(*this)); else MediaSessionHelper::resetSharedHelper(); #endif #if ENABLE(LEGACY_ENCRYPTED_MEDIA) if (useGPUProcessForMedia) legacyCDMFactory().registerFactory(); else LegacyCDM::resetFactories(); #endif if (useGPUProcessForMedia) mediaEngineConfigurationFactory().registerFactory(); else MediaEngineConfigurationFactory::resetFactories(); if (useGPUProcessForMedia) WebCore::AudioHardwareListener::setCreationFunction([this] (WebCore::AudioHardwareListener::Client& client) { return RemoteAudioHardwareListener::create(client, *this); }); else WebCore::AudioHardwareListener::resetCreationFunction(); if (useGPUProcessForMedia) WebCore::RemoteCommandListener::setCreationFunction([this] (WebCore::RemoteCommandListenerClient& client) { return RemoteRemoteCommandListener::create(client, *this); }); else WebCore::RemoteCommandListener::resetCreationFunction(); #if PLATFORM(COCOA) if (useGPUProcessForMedia) { SystemBatteryStatusTestingOverrides::singleton().setConfigurationChangedCallback([this] () { ensureGPUProcessConnection().updateMediaConfiguration(); }); #if ENABLE(VP9) VP9TestingOverrides::singleton().setConfigurationChangedCallback([this] () { ensureGPUProcessConnection().updateMediaConfiguration(); }); #endif } else { SystemBatteryStatusTestingOverrides::singleton().setConfigurationChangedCallback(nullptr); #if ENABLE(VP9) VP9TestingOverrides::singleton().setConfigurationChangedCallback(nullptr); #endif } #endif } bool WebProcess::shouldUseRemoteRenderingFor(RenderingPurpose purpose) { switch (purpose) { case RenderingPurpose::Canvas: return m_useGPUProcessForCanvasRendering; case RenderingPurpose::DOM: return m_useGPUProcessForDOMRendering; case RenderingPurpose::MediaPainting: return m_useGPUProcessForMedia; default: break; } return false; } #if ENABLE(WEBGL) void WebProcess::setUseGPUProcessForWebGL(bool useGPUProcessForWebGL) { m_useGPUProcessForWebGL = useGPUProcessForWebGL; } bool WebProcess::shouldUseRemoteRenderingForWebGL() const { return m_useGPUProcessForWebGL; } #endif #endif #if ENABLE(MEDIA_STREAM) SpeechRecognitionRealtimeMediaSourceManager& WebProcess::ensureSpeechRecognitionRealtimeMediaSourceManager() { if (!m_speechRecognitionRealtimeMediaSourceManager) m_speechRecognitionRealtimeMediaSourceManager = makeUnique(*parentProcessConnection()); return *m_speechRecognitionRealtimeMediaSourceManager; } #endif #if ENABLE(GPU_PROCESS) && ENABLE(LEGACY_ENCRYPTED_MEDIA) RemoteLegacyCDMFactory& WebProcess::legacyCDMFactory() { return *supplement(); } #endif #if ENABLE(GPU_PROCESS) && ENABLE(ENCRYPTED_MEDIA) RemoteCDMFactory& WebProcess::cdmFactory() { return *supplement(); } #endif #if ENABLE(GPU_PROCESS) RemoteMediaEngineConfigurationFactory& WebProcess::mediaEngineConfigurationFactory() { return *supplement(); } #endif } // namespace WebKit #undef RELEASE_LOG_SESSION_ID #undef WEBPROCESS_RELEASE_LOG #undef WEBPROCESS_RELEASE_LOG_ERROR