3d3845079e466c7c41e48b92716155817a05de41
[WebKit.git] / Source / WebKit / UIProcess / Cocoa / WebProcessPoolCocoa.mm
1 /*
2  * Copyright (C) 2010-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 #import "config.h"
27 #import "WebProcessPool.h"
28
29 #import "CookieStorageUtilsCF.h"
30 #import "LegacyCustomProtocolManagerClient.h"
31 #import "Logging.h"
32 #import "NetworkProcessCreationParameters.h"
33 #import "NetworkProcessMessages.h"
34 #import "NetworkProcessProxy.h"
35 #import "PluginProcessManager.h"
36 #import "SandboxUtilities.h"
37 #import "TextChecker.h"
38 #import "VersionChecks.h"
39 #import "WKBrowsingContextControllerInternal.h"
40 #import "WebBackForwardCache.h"
41 #import "WebMemoryPressureHandler.h"
42 #import "WebPageGroup.h"
43 #import "WebPreferencesKeys.h"
44 #import "WebProcessCache.h"
45 #import "WebProcessCreationParameters.h"
46 #import "WebProcessMessages.h"
47 #import "WindowServerConnection.h"
48 #import <WebCore/Color.h>
49 #import <WebCore/NetworkStorageSession.h>
50 #import <WebCore/NotImplemented.h>
51 #import <WebCore/PlatformPasteboard.h>
52 #import <WebCore/RuntimeApplicationChecks.h>
53 #import <WebCore/SharedBuffer.h>
54 #import <objc/runtime.h>
55 #import <pal/spi/cf/CFNetworkSPI.h>
56 #import <pal/spi/cocoa/NSKeyedArchiverSPI.h>
57 #import <sys/param.h>
58 #import <wtf/FileSystem.h>
59 #import <wtf/ProcessPrivilege.h>
60 #import <wtf/SoftLinking.h>
61 #import <wtf/cocoa/Entitlements.h>
62 #import <wtf/spi/darwin/dyldSPI.h>
63
64 #if PLATFORM(MAC)
65 #import <QuartzCore/CARemoteLayerServer.h>
66 #else
67 #import "AccessibilitySupportSPI.h"
68 #import "UIKitSPI.h"
69 #endif
70
71 #if PLATFORM(IOS)
72 #import <sys/utsname.h>
73 #endif
74
75 #if PLATFORM(COCOA)
76 #import <pal/spi/cocoa/NEFilterSourceSPI.h>
77
78 SOFT_LINK_FRAMEWORK_OPTIONAL(NetworkExtension);
79 SOFT_LINK_CLASS_OPTIONAL(NetworkExtension, NEFilterSource);
80 #endif
81
82 NSString *WebServiceWorkerRegistrationDirectoryDefaultsKey = @"WebServiceWorkerRegistrationDirectory";
83 NSString *WebKitLocalCacheDefaultsKey = @"WebKitLocalCache";
84 NSString *WebKitJSCJITEnabledDefaultsKey = @"WebKitJSCJITEnabledDefaultsKey";
85 NSString *WebKitJSCFTLJITEnabledDefaultsKey = @"WebKitJSCFTLJITEnabledDefaultsKey";
86
87 #if !PLATFORM(IOS_FAMILY)
88 static NSString *WebKitApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification = @"NSApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification";
89 #endif
90
91 static NSString * const WebKitSuppressMemoryPressureHandlerDefaultsKey = @"WebKitSuppressMemoryPressureHandler";
92
93 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
94 static NSString * const WebKitLogCookieInformationDefaultsKey = @"WebKitLogCookieInformation";
95 #endif
96
97 #if PLATFORM(IOS)
98 SOFT_LINK_PRIVATE_FRAMEWORK(BackBoardServices)
99 SOFT_LINK(BackBoardServices, BKSDisplayBrightnessGetCurrent, float, (), ());
100 #endif
101
102 namespace WebKit {
103 using namespace WebCore;
104
105 static void registerUserDefaultsIfNeeded()
106 {
107     static bool didRegister;
108     if (didRegister)
109         return;
110
111     didRegister = true;
112     NSMutableDictionary *registrationDictionary = [NSMutableDictionary dictionary];
113     
114     [registrationDictionary setObject:@YES forKey:WebKitJSCJITEnabledDefaultsKey];
115     [registrationDictionary setObject:@YES forKey:WebKitJSCFTLJITEnabledDefaultsKey];
116
117     [[NSUserDefaults standardUserDefaults] registerDefaults:registrationDictionary];
118 }
119
120 void WebProcessPool::updateProcessSuppressionState()
121 {
122     if (m_networkProcess)
123         m_networkProcess->setProcessSuppressionEnabled(processSuppressionEnabled());
124
125 #if ENABLE(NETSCAPE_PLUGIN_API)
126     if (!m_processSuppressionDisabledForPageCounter.value())
127         m_pluginProcessManagerProcessSuppressionDisabledToken = nullptr;
128     else if (!m_pluginProcessManagerProcessSuppressionDisabledToken)
129         m_pluginProcessManagerProcessSuppressionDisabledToken = PluginProcessManager::singleton().processSuppressionDisabledToken();
130 #endif
131 }
132
133 NSMutableDictionary *WebProcessPool::ensureBundleParameters()
134 {
135     if (!m_bundleParameters)
136         m_bundleParameters = adoptNS([[NSMutableDictionary alloc] init]);
137
138     return m_bundleParameters.get();
139 }
140
141 void WebProcessPool::platformInitialize()
142 {
143     registerUserDefaultsIfNeeded();
144     registerNotificationObservers();
145     initializeClassesForParameterCoding();
146
147     // FIXME: This should be able to share code with WebCore's MemoryPressureHandler (and be platform independent).
148     // Right now it cannot because WebKit1 and WebKit2 need to be able to coexist in the UI process,
149     // and you can only have one WebCore::MemoryPressureHandler.
150
151     if (![[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitSuppressMemoryPressureHandler"])
152         installMemoryPressureHandler();
153
154     setLegacyCustomProtocolManagerClient(makeUnique<LegacyCustomProtocolManagerClient>());
155 }
156
157 #if PLATFORM(IOS_FAMILY)
158 String WebProcessPool::cookieStorageDirectory()
159 {
160     String path = pathForProcessContainer();
161     if (path.isEmpty())
162         path = NSHomeDirectory();
163
164     path = path + "/Library/Cookies";
165     path = stringByResolvingSymlinksInPath(path);
166     return path;
167 }
168 #endif
169
170 void WebProcessPool::platformResolvePathsForSandboxExtensions()
171 {
172     m_resolvedPaths.uiProcessBundleResourcePath = resolvePathForSandboxExtension([[NSBundle mainBundle] resourcePath]);
173
174 #if PLATFORM(IOS_FAMILY)
175     m_resolvedPaths.cookieStorageDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(WebProcessPool::cookieStorageDirectory());
176     m_resolvedPaths.containerCachesDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(WebProcessPool::webContentCachesDirectory());
177     m_resolvedPaths.containerTemporaryDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(WebProcessPool::containerTemporaryDirectory());
178 #endif
179 }
180
181 #if PLATFORM(IOS)
182 static bool deviceHasAGXCompilerService()
183 {
184     static bool deviceHasAGXCompilerService = false;
185     static std::once_flag flag;
186     std::call_once(
187         flag,
188         [] () {
189             struct utsname systemInfo;
190             if (uname(&systemInfo))
191                 return;
192             const char* machine = systemInfo.machine;
193             if (!strcmp(machine, "iPad5,1") || !strcmp(machine, "iPad5,2") || !strcmp(machine, "iPad5,3") || !strcmp(machine, "iPad5,4"))
194                 deviceHasAGXCompilerService = true;
195         });
196     return deviceHasAGXCompilerService;
197 }
198 #endif
199
200 void WebProcessPool::platformInitializeWebProcess(const WebProcessProxy& process, WebProcessCreationParameters& parameters)
201 {
202     parameters.mediaMIMETypes = process.mediaMIMETypes();
203
204 #if PLATFORM(MAC)
205     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
206     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
207     parameters.accessibilityEnhancedUserInterfaceEnabled = [[NSApp accessibilityAttributeValue:@"AXEnhancedUserInterface"] boolValue];
208     ALLOW_DEPRECATED_DECLARATIONS_END
209 #else
210     parameters.accessibilityEnhancedUserInterfaceEnabled = false;
211 #endif
212
213     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
214
215     parameters.shouldEnableJIT = [defaults boolForKey:WebKitJSCJITEnabledDefaultsKey];
216     parameters.shouldEnableFTLJIT = [defaults boolForKey:WebKitJSCFTLJITEnabledDefaultsKey];
217     parameters.shouldEnableMemoryPressureReliefLogging = [defaults boolForKey:@"LogMemoryJetsamDetails"];
218     parameters.shouldSuppressMemoryPressureHandler = [defaults boolForKey:WebKitSuppressMemoryPressureHandlerDefaultsKey];
219
220 #if HAVE(HOSTED_CORE_ANIMATION)
221 #if !PLATFORM(IOS_FAMILY)
222     parameters.acceleratedCompositingPort = MachSendRight::create([CARemoteLayerServer sharedServer].serverPort);
223 #endif
224 #endif
225
226     // FIXME: This should really be configurable; we shouldn't just blindly allow read access to the UI process bundle.
227     parameters.uiProcessBundleResourcePath = m_resolvedPaths.uiProcessBundleResourcePath;
228     SandboxExtension::createHandleWithoutResolvingPath(parameters.uiProcessBundleResourcePath, SandboxExtension::Type::ReadOnly, parameters.uiProcessBundleResourcePathExtensionHandle);
229
230     parameters.uiProcessBundleIdentifier = String([[NSBundle mainBundle] bundleIdentifier]);
231     parameters.uiProcessSDKVersion = dyld_get_program_sdk_version();
232
233 #if PLATFORM(IOS_FAMILY)
234     if (!m_resolvedPaths.cookieStorageDirectory.isEmpty())
235         SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.cookieStorageDirectory, SandboxExtension::Type::ReadWrite, parameters.cookieStorageDirectoryExtensionHandle);
236
237     if (!m_resolvedPaths.containerCachesDirectory.isEmpty())
238         SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.containerCachesDirectory, SandboxExtension::Type::ReadWrite, parameters.containerCachesDirectoryExtensionHandle);
239
240     if (!m_resolvedPaths.containerTemporaryDirectory.isEmpty())
241         SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.containerTemporaryDirectory, SandboxExtension::Type::ReadWrite, parameters.containerTemporaryDirectoryExtensionHandle);
242 #endif
243
244     parameters.fontWhitelist = m_fontWhitelist;
245
246     if (m_bundleParameters) {
247         auto keyedArchiver = secureArchiver();
248
249         @try {
250             [keyedArchiver encodeObject:m_bundleParameters.get() forKey:@"parameters"];
251             [keyedArchiver finishEncoding];
252         } @catch (NSException *exception) {
253             LOG_ERROR("Failed to encode bundle parameters: %@", exception);
254         }
255
256         auto data = keyedArchiver.get().encodedData;
257
258         parameters.bundleParameterData = API::Data::createWithoutCopying(WTFMove(data));
259     }
260     parameters.networkATSContext = adoptCF(_CFNetworkCopyATSContext());
261
262 #if ENABLE(MEDIA_STREAM)
263     // Allow microphone access if either preference is set because WebRTC requires microphone access.
264     bool mediaDevicesEnabled = m_defaultPageGroup->preferences().mediaDevicesEnabled();
265     bool webRTCEnabled = m_defaultPageGroup->preferences().peerConnectionEnabled();
266     if ([defaults objectForKey:@"ExperimentalPeerConnectionEnabled"])
267         webRTCEnabled = [defaults boolForKey:@"ExperimentalPeerConnectionEnabled"];
268
269     bool isSafari = false;
270 #if PLATFORM(IOS_FAMILY)
271     if (WebCore::IOSApplication::isMobileSafari())
272         isSafari = true;
273 #elif PLATFORM(MAC)
274     if (WebCore::MacApplication::isSafari())
275         isSafari = true;
276 #endif
277
278 #if !LOG_DISABLED || !RELEASE_LOG_DISABLED
279     parameters.webCoreLoggingChannels = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebCoreLogging"];
280     parameters.webKitLoggingChannels = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebKit2Logging"];
281 #endif
282
283     // FIXME: Remove this and related parameter when <rdar://problem/29448368> is fixed.
284     if (isSafari && !parameters.shouldCaptureAudioInUIProcess && mediaDevicesEnabled)
285         SandboxExtension::createHandleForGenericExtension("com.apple.webkit.microphone", parameters.audioCaptureExtensionHandle);
286 #endif
287
288 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED
289     parameters.shouldLogUserInteraction = [defaults boolForKey:WebKitLogCookieInformationDefaultsKey];
290 #endif
291     
292 #if PLATFORM(MAC)
293     auto screenProperties = WebCore::collectScreenProperties();
294     parameters.screenProperties = WTFMove(screenProperties);
295     parameters.useOverlayScrollbars = ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay);
296 #endif
297     
298 #if PLATFORM(IOS)
299     if (deviceHasAGXCompilerService()) {
300         SandboxExtension::Handle compilerServiceExtensionHandle;
301         SandboxExtension::createHandleForMachLookup("com.apple.AGXCompilerService", WTF::nullopt, compilerServiceExtensionHandle);
302         parameters.compilerServiceExtensionHandle = WTFMove(compilerServiceExtensionHandle);
303     }
304 #endif
305     
306 #if PLATFORM(COCOA)
307     if ([getNEFilterSourceClass() filterRequired]) {
308         SandboxExtension::Handle handle;
309         SandboxExtension::createHandleForMachLookup("com.apple.nehelper", WTF::nullopt, handle);
310         parameters.neHelperExtensionHandle = WTFMove(handle);
311         SandboxExtension::createHandleForMachLookup("com.apple.nesessionmanager.content-filter", WTF::nullopt, handle);
312         parameters.neSessionManagerExtensionHandle = WTFMove(handle);
313     }
314 #endif
315 }
316
317 void WebProcessPool::platformInitializeNetworkProcess(NetworkProcessCreationParameters& parameters)
318 {
319     parameters.uiProcessBundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
320     parameters.uiProcessSDKVersion = dyld_get_program_sdk_version();
321
322     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
323
324     {
325         bool isSafari = false;
326 #if PLATFORM(IOS_FAMILY)
327         isSafari = WebCore::IOSApplication::isMobileSafari();
328 #elif PLATFORM(MAC)
329         isSafari = WebCore::MacApplication::isSafari();
330 #endif
331         if (isSafari) {
332             parameters.defaultDataStoreParameters.networkSessionParameters.httpProxy = URL(URL(), [defaults stringForKey:(NSString *)WebKit2HTTPProxyDefaultsKey]);
333             parameters.defaultDataStoreParameters.networkSessionParameters.httpsProxy = URL(URL(), [defaults stringForKey:(NSString *)WebKit2HTTPSProxyDefaultsKey]);
334         }
335     }
336
337     parameters.enableLegacyTLS = false;
338     if (id value = [defaults objectForKey:@"WebKitEnableLegacyTLS"])
339         parameters.enableLegacyTLS = [value boolValue];
340     parameters.defaultDataStoreParameters.networkSessionParameters.enableLegacyTLS = parameters.enableLegacyTLS;
341
342     parameters.networkATSContext = adoptCF(_CFNetworkCopyATSContext());
343
344 #if PLATFORM(IOS_FAMILY)
345     parameters.ctDataConnectionServiceType = m_configuration->ctDataConnectionServiceType();
346 #endif
347
348     parameters.shouldSuppressMemoryPressureHandler = [defaults boolForKey:WebKitSuppressMemoryPressureHandlerDefaultsKey];
349
350 #if PLATFORM(MAC)
351     ASSERT(parameters.uiProcessCookieStorageIdentifier.isEmpty());
352     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
353     parameters.uiProcessCookieStorageIdentifier = identifyingDataFromCookieStorage([[NSHTTPCookieStorage sharedHTTPCookieStorage] _cookieStorage]);
354 #endif
355
356     parameters.storageAccessAPIEnabled = storageAccessAPIEnabled();
357     parameters.suppressesConnectionTerminationOnSystemChange = m_configuration->suppressesConnectionTerminationOnSystemChange();
358
359     parameters.shouldEnableITPDatabase = [defaults boolForKey:[NSString stringWithFormat:@"InternalDebug%@", WebPreferencesKey::isITPDatabaseEnabledKey().createCFString().get()]];
360
361     parameters.enableAdClickAttributionDebugMode = [defaults boolForKey:[NSString stringWithFormat:@"Experimental%@", WebPreferencesKey::adClickAttributionDebugModeEnabledKey().createCFString().get()]];
362 }
363
364 void WebProcessPool::platformInvalidateContext()
365 {
366     unregisterNotificationObservers();
367 }
368
369 #if PLATFORM(IOS_FAMILY)
370 String WebProcessPool::parentBundleDirectory()
371 {
372     return [[[NSBundle mainBundle] bundlePath] stringByStandardizingPath];
373 }
374
375 String WebProcessPool::networkingCachesDirectory()
376 {
377     String path = pathForProcessContainer();
378     if (path.isEmpty())
379         path = NSHomeDirectory();
380
381     path = path + "/Library/Caches/com.apple.WebKit.Networking/";
382     path = stringByResolvingSymlinksInPath(path);
383
384     NSError *error = nil;
385     NSString* nsPath = path;
386     if (![[NSFileManager defaultManager] createDirectoryAtPath:nsPath withIntermediateDirectories:YES attributes:nil error:&error]) {
387         NSLog(@"could not create networking caches directory \"%@\", error %@", nsPath, error);
388         return String();
389     }
390
391     return path;
392 }
393
394 String WebProcessPool::webContentCachesDirectory()
395 {
396     String path = pathForProcessContainer();
397     if (path.isEmpty())
398         path = NSHomeDirectory();
399
400     path = path + "/Library/Caches/com.apple.WebKit.WebContent/";
401     path = stringByResolvingSymlinksInPath(path);
402
403     NSError *error = nil;
404     NSString* nsPath = path;
405     if (![[NSFileManager defaultManager] createDirectoryAtPath:nsPath withIntermediateDirectories:YES attributes:nil error:&error]) {
406         NSLog(@"could not create web content caches directory \"%@\", error %@", nsPath, error);
407         return String();
408     }
409
410     return path;
411 }
412
413 String WebProcessPool::containerTemporaryDirectory()
414 {
415     String path = NSTemporaryDirectory();
416     return stringByResolvingSymlinksInPath(path);
417 }
418 #endif
419
420 #if PLATFORM(IOS_FAMILY)
421 void WebProcessPool::setJavaScriptConfigurationFileEnabledFromDefaults()
422 {
423     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
424
425     setJavaScriptConfigurationFileEnabled([defaults boolForKey:@"WebKitJavaScriptCoreUseConfigFile"]);
426 }
427 #endif
428
429 bool WebProcessPool::omitPDFSupport()
430 {
431     // Since this is a "secret default" we don't bother registering it.
432     return [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
433 }
434
435 bool WebProcessPool::processSuppressionEnabled() const
436 {
437     return !m_userObservablePageCounter.value() && !m_processSuppressionDisabledForPageCounter.value();
438 }
439
440 bool WebProcessPool::networkProcessHasEntitlementForTesting(const String& entitlement)
441 {
442     return WTF::hasEntitlement(ensureNetworkProcess().connection()->xpcConnection(), entitlement.utf8().data());
443 }
444
445 #if PLATFORM(IOS)
446 float WebProcessPool::displayBrightness()
447 {
448     return BKSDisplayBrightnessGetCurrent();
449 }
450     
451 void WebProcessPool::backlightLevelDidChangeCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
452 {
453     WebProcessPool* pool = reinterpret_cast<WebProcessPool*>(observer);
454     pool->sendToAllProcesses(Messages::WebProcess::BacklightLevelDidChange(BKSDisplayBrightnessGetCurrent()));
455 }
456 #endif
457
458 void WebProcessPool::registerNotificationObservers()
459 {
460 #if !PLATFORM(IOS_FAMILY)
461     // Listen for enhanced accessibility changes and propagate them to the WebProcess.
462     m_enhancedAccessibilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:WebKitApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) {
463         setEnhancedAccessibility([[[note userInfo] objectForKey:@"AXEnhancedUserInterface"] boolValue]);
464     }];
465
466     m_automaticTextReplacementNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticTextReplacementNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
467         TextChecker::didChangeAutomaticTextReplacementEnabled();
468         textCheckerStateChanged();
469     }];
470     
471     m_automaticSpellingCorrectionNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticSpellingCorrectionNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
472         TextChecker::didChangeAutomaticSpellingCorrectionEnabled();
473         textCheckerStateChanged();
474     }];
475
476     m_automaticQuoteSubstitutionNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticQuoteSubstitutionNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
477         TextChecker::didChangeAutomaticQuoteSubstitutionEnabled();
478         textCheckerStateChanged();
479     }];
480
481     m_automaticDashSubstitutionNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSSpellCheckerDidChangeAutomaticDashSubstitutionNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
482         TextChecker::didChangeAutomaticDashSubstitutionEnabled();
483         textCheckerStateChanged();
484     }];
485
486     m_accessibilityDisplayOptionsNotificationObserver = [[NSWorkspace.sharedWorkspace notificationCenter] addObserverForName:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
487         screenPropertiesStateChanged();
488     }];
489
490 #if ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
491     m_scrollerStyleNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSPreferredScrollerStyleDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
492         auto scrollbarStyle = [NSScroller preferredScrollerStyle];
493         sendToAllProcesses(Messages::WebProcess::ScrollerStylePreferenceChanged(scrollbarStyle));
494     }];
495 #endif
496
497     m_activationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidBecomeActiveNotification object:NSApp queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
498         setApplicationIsActive(true);
499     }];
500
501     m_deactivationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidResignActiveNotification object:NSApp queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
502         setApplicationIsActive(false);
503     }];
504 #elif PLATFORM(IOS)
505     CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), this, backlightLevelDidChangeCallback, static_cast<CFStringRef>(UIBacklightLevelChangedNotification), nullptr, CFNotificationSuspensionBehaviorCoalesce);
506     m_accessibilityEnabledObserver = [[NSNotificationCenter defaultCenter] addObserverForName:(__bridge id)kAXSApplicationAccessibilityEnabledNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *) {
507         for (size_t i = 0; i < m_processes.size(); ++i)
508             m_processes[i]->unblockAccessibilityServerIfNeeded();
509     }];
510 #endif // !PLATFORM(IOS_FAMILY)
511 }
512
513 void WebProcessPool::unregisterNotificationObservers()
514 {
515 #if !PLATFORM(IOS_FAMILY)
516     [[NSNotificationCenter defaultCenter] removeObserver:m_enhancedAccessibilityObserver.get()];
517     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticTextReplacementNotificationObserver.get()];
518     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticSpellingCorrectionNotificationObserver.get()];
519     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticQuoteSubstitutionNotificationObserver.get()];
520     [[NSNotificationCenter defaultCenter] removeObserver:m_automaticDashSubstitutionNotificationObserver.get()];
521     [[NSWorkspace.sharedWorkspace notificationCenter] removeObserver:m_accessibilityDisplayOptionsNotificationObserver.get()];
522 #if ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
523     [[NSNotificationCenter defaultCenter] removeObserver:m_scrollerStyleNotificationObserver.get()];
524 #endif
525     [[NSNotificationCenter defaultCenter] removeObserver:m_activationObserver.get()];
526     [[NSNotificationCenter defaultCenter] removeObserver:m_deactivationObserver.get()];
527 #elif PLATFORM(IOS)
528     CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), this, static_cast<CFStringRef>(UIBacklightLevelChangedNotification) , nullptr);
529     [[NSNotificationCenter defaultCenter] removeObserver:m_accessibilityEnabledObserver.get()];
530 #endif // !PLATFORM(IOS_FAMILY)
531 }
532
533 static CFURLStorageSessionRef privateBrowsingSession()
534 {
535     static CFURLStorageSessionRef session;
536     static dispatch_once_t once;
537     dispatch_once(&once, ^{
538         NSString *identifier = [NSString stringWithFormat:@"%@.PrivateBrowsing", [[NSBundle mainBundle] bundleIdentifier]];
539         session = createPrivateStorageSession((__bridge CFStringRef)identifier);
540     });
541
542     return session;
543 }
544
545 bool WebProcessPool::isURLKnownHSTSHost(const String& urlString) const
546 {
547     RetainPtr<CFURLRef> url = URL(URL(), urlString).createCFURL();
548
549     return _CFNetworkIsKnownHSTSHostWithSession(url.get(), nullptr);
550 }
551
552 void WebProcessPool::resetHSTSHosts()
553 {
554     _CFNetworkResetHSTSHostsWithSession(nullptr);
555     _CFNetworkResetHSTSHostsWithSession(privateBrowsingSession());
556 }
557
558 void WebProcessPool::resetHSTSHostsAddedAfterDate(double startDateIntervalSince1970)
559 {
560     NSDate *startDate = [NSDate dateWithTimeIntervalSince1970:startDateIntervalSince1970];
561     _CFNetworkResetHSTSHostsSinceDate(nullptr, (__bridge CFDateRef)startDate);
562     _CFNetworkResetHSTSHostsSinceDate(privateBrowsingSession(), (__bridge CFDateRef)startDate);
563 }
564
565 #if PLATFORM(MAC) && ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
566 void WebProcessPool::startDisplayLink(IPC::Connection& connection, unsigned observerID, uint32_t displayID)
567 {
568     for (auto& displayLink : m_displayLinks) {
569         if (displayLink->displayID() == displayID) {
570             displayLink->addObserver(connection, observerID);
571             return;
572         }
573     }
574     auto displayLink = makeUnique<DisplayLink>(displayID);
575     displayLink->addObserver(connection, observerID);
576     m_displayLinks.append(WTFMove(displayLink));
577 }
578
579 void WebProcessPool::stopDisplayLink(IPC::Connection& connection, unsigned observerID, uint32_t displayID)
580 {
581     for (auto& displayLink : m_displayLinks) {
582         if (displayLink->displayID() == displayID) {
583             displayLink->removeObserver(connection, observerID);
584             return;
585         }
586     }
587 }
588
589 void WebProcessPool::stopDisplayLinks(IPC::Connection& connection)
590 {
591     for (auto& displayLink : m_displayLinks)
592         displayLink->removeObservers(connection);
593 }
594 #endif
595
596 // FIXME: Deprecated. Left here until a final decision is made.
597 void WebProcessPool::setCookieStoragePartitioningEnabled(bool enabled)
598 {
599     m_cookieStoragePartitioningEnabled = enabled;
600 }
601
602 void WebProcessPool::clearPermanentCredentialsForProtectionSpace(WebCore::ProtectionSpace&& protectionSpace)
603 {
604     auto sharedStorage = [NSURLCredentialStorage sharedCredentialStorage];
605     auto credentials = [sharedStorage credentialsForProtectionSpace:protectionSpace.nsSpace()];
606     for (NSString* user in credentials) {
607         auto credential = credentials[user];
608         if (credential.persistence == NSURLCredentialPersistencePermanent)
609             [sharedStorage removeCredential:credentials[user] forProtectionSpace:protectionSpace.nsSpace()];
610     }
611 }
612
613 int networkProcessLatencyQOS()
614 {
615     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitNetworkProcessLatencyQOS"];
616     return qos;
617 }
618
619 int networkProcessThroughputQOS()
620 {
621     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitNetworkProcessThroughputQOS"];
622     return qos;
623 }
624
625 int webProcessLatencyQOS()
626 {
627     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitWebProcessLatencyQOS"];
628     return qos;
629 }
630
631 int webProcessThroughputQOS()
632 {
633     static const int qos = [[NSUserDefaults standardUserDefaults] integerForKey:@"WebKitWebProcessThroughputQOS"];
634     return qos;
635 }
636
637 #if PLATFORM(IOS_FAMILY)
638 void WebProcessPool::applicationIsAboutToSuspend()
639 {
640     RELEASE_LOG(ProcessSuspension, "WebProcessPool::applicationIsAboutToSuspend() Terminating non-critical processes");
641
642     m_backForwardCache->pruneToSize(1);
643     m_webProcessCache->clear();
644 }
645
646 void WebProcessPool::notifyProcessPoolsApplicationIsAboutToSuspend()
647 {
648     for (auto* processPool : allProcessPools())
649         processPool->applicationIsAboutToSuspend();
650 }
651 #endif
652
653 void WebProcessPool::initializeClassesForParameterCoding()
654 {
655     const auto& customClasses = m_configuration->customClassesForParameterCoder();
656     if (customClasses.isEmpty())
657         return;
658
659     auto standardClasses = [NSSet setWithObjects:[NSArray class], [NSData class], [NSDate class], [NSDictionary class], [NSNull class],
660         [NSNumber class], [NSSet class], [NSString class], [NSTimeZone class], [NSURL class], [NSUUID class], nil];
661     
662     auto mutableSet = adoptNS([standardClasses mutableCopy]);
663
664     for (const auto& customClass : customClasses) {
665         const auto* className = customClass.utf8().data();
666         Class objectClass = objc_lookUpClass(className);
667         if (!objectClass) {
668             WTFLogAlways("InjectedBundle::extendClassesForParameterCoder - Class %s is not a valid Objective C class.\n", className);
669             break;
670         }
671
672         [mutableSet.get() addObject:objectClass];
673     }
674
675     m_classesForParameterCoder = mutableSet;
676 }
677
678 NSSet *WebProcessPool::allowedClassesForParameterCoding() const
679 {
680     return m_classesForParameterCoder.get();
681 }
682
683 } // namespace WebKit