1/*
2 * Copyright (C) 2009, 2010, 2012, 2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebProcess.h"
28
29#include "APIFrameHandle.h"
30#include "AuthenticationManager.h"
31#include "DrawingArea.h"
32#include "EventDispatcher.h"
33#include "InjectedBundle.h"
34#include "InjectedBundleUserMessageCoders.h"
35#include "Logging.h"
36#include "PluginProcessConnectionManager.h"
37#include "SessionTracker.h"
38#include "StatisticsData.h"
39#include "UserData.h"
40#include "WebApplicationCacheManager.h"
41#include "WebConnectionToUIProcess.h"
42#include "WebContextMessages.h"
43#include "WebCookieManager.h"
44#include "WebCoreArgumentCoders.h"
45#include "WebFrame.h"
46#include "WebFrameNetworkingContext.h"
47#include "WebGeolocationManager.h"
48#include "WebIconDatabaseProxy.h"
49#include "WebMediaCacheManager.h"
50#include "WebMemorySampler.h"
51#include "WebPage.h"
52#include "WebPageCreationParameters.h"
53#include "WebPageGroupProxyMessages.h"
54#include "WebPlatformStrategies.h"
55#include "WebProcessCreationParameters.h"
56#include "WebProcessMessages.h"
57#include "WebProcessProxyMessages.h"
58#include "WebResourceCacheManager.h"
59#include <JavaScriptCore/JSLock.h>
60#include <JavaScriptCore/MemoryStatistics.h>
61#include <WebCore/AXObjectCache.h>
62#include <WebCore/ApplicationCacheStorage.h>
63#include <WebCore/AuthenticationChallenge.h>
64#include <WebCore/CrossOriginPreflightResultCache.h>
65#include <WebCore/Font.h>
66#include <WebCore/FontCache.h>
67#include <WebCore/Frame.h>
68#include <WebCore/FrameLoader.h>
69#include <WebCore/GCController.h>
70#include <WebCore/GlyphPageTreeNode.h>
71#include <WebCore/IconDatabase.h>
72#include <WebCore/JSDOMWindow.h>
73#include <WebCore/Language.h>
74#include <WebCore/MemoryCache.h>
75#include <WebCore/MemoryPressureHandler.h>
76#include <WebCore/Page.h>
77#include <WebCore/PageCache.h>
78#include <WebCore/PageGroup.h>
79#include <WebCore/ResourceHandle.h>
80#include <WebCore/SchemeRegistry.h>
81#include <WebCore/SecurityOrigin.h>
82#include <WebCore/Settings.h>
83#include <WebCore/StorageTracker.h>
84#include <unistd.h>
85#include <wtf/CurrentTime.h>
86#include <wtf/HashCountedSet.h>
87#include <wtf/PassRefPtr.h>
88#include <wtf/RunLoop.h>
89#include <wtf/text/StringHash.h>
90
91#if ENABLE(NETWORK_PROCESS)
92#if PLATFORM(COCOA)
93#include "CookieStorageShim.h"
94#endif
95#include "NetworkProcessConnection.h"
96#endif
97
98#if ENABLE(SEC_ITEM_SHIM)
99#include "SecItemShim.h"
100#endif
101
102#if ENABLE(CUSTOM_PROTOCOLS)
103#include "CustomProtocolManager.h"
104#endif
105
106#if ENABLE(DATABASE_PROCESS)
107#include "WebToDatabaseProcessConnection.h"
108#endif
109
110#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
111#include "WebNotificationManager.h"
112#endif
113
114#if ENABLE(SQL_DATABASE)
115#include "WebDatabaseManager.h"
116#endif
117
118#if ENABLE(BATTERY_STATUS)
119#include "WebBatteryManager.h"
120#endif
121
122#if ENABLE(NETWORK_PROCESS)
123#include "WebResourceLoadScheduler.h"
124#endif
125
126#if ENABLE(REMOTE_INSPECTOR)
127#include <JavaScriptCore/RemoteInspector.h>
128#endif
129
130#if USE(SOUP) && !ENABLE(CUSTOM_PROTOCOLS)
131#include "WebSoupRequestManager.h"
132#endif
133
134using namespace JSC;
135using namespace WebCore;
136
137// This should be less than plugInAutoStartExpirationTimeThreshold in PlugInAutoStartProvider.
138static const double plugInAutoStartExpirationTimeUpdateThreshold = 29 * 24 * 60 * 60;
139
140// This should be greater than tileRevalidationTimeout in TileController.
141static const double nonVisibleProcessCleanupDelay = 10;
142
143namespace WebKit {
144
145WebProcess& WebProcess::shared()
146{
147    static WebProcess& process = *new WebProcess;
148    return process;
149}
150
151WebProcess::WebProcess()
152    : m_eventDispatcher(EventDispatcher::create())
153#if PLATFORM(IOS)
154    , m_viewUpdateDispatcher(ViewUpdateDispatcher::create())
155#endif
156    , m_processSuspensionCleanupTimer(this, &WebProcess::processSuspensionCleanupTimerFired)
157    , m_inDidClose(false)
158    , m_hasSetCacheModel(false)
159    , m_cacheModel(CacheModelDocumentViewer)
160#if PLATFORM(COCOA)
161    , m_compositingRenderServerPort(MACH_PORT_NULL)
162    , m_clearResourceCachesDispatchGroup(0)
163#endif
164    , m_fullKeyboardAccessEnabled(false)
165    , m_textCheckerState()
166    , m_iconDatabaseProxy(new WebIconDatabaseProxy(this))
167#if ENABLE(NETWORK_PROCESS)
168    , m_usesNetworkProcess(false)
169    , m_webResourceLoadScheduler(new WebResourceLoadScheduler)
170#endif
171#if ENABLE(NETSCAPE_PLUGIN_API)
172    , m_pluginProcessConnectionManager(PluginProcessConnectionManager::create())
173#endif
174#if ENABLE(SERVICE_CONTROLS)
175    , m_hasImageServices(false)
176    , m_hasSelectionServices(false)
177    , m_hasRichContentServices(false)
178#endif
179    , m_nonVisibleProcessCleanupTimer(this, &WebProcess::nonVisibleProcessCleanupTimerFired)
180{
181    // Initialize our platform strategies.
182    WebPlatformStrategies::initialize();
183
184    // FIXME: This should moved to where WebProcess::initialize is called,
185    // so that ports have a chance to customize, and ifdefs in this file are
186    // limited.
187    addSupplement<WebGeolocationManager>();
188    addSupplement<WebApplicationCacheManager>();
189    addSupplement<WebResourceCacheManager>();
190    addSupplement<WebCookieManager>();
191    addSupplement<WebMediaCacheManager>();
192    addSupplement<AuthenticationManager>();
193
194#if ENABLE(SQL_DATABASE)
195    addSupplement<WebDatabaseManager>();
196#endif
197#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
198    addSupplement<WebNotificationManager>();
199#endif
200#if ENABLE(CUSTOM_PROTOCOLS)
201    addSupplement<CustomProtocolManager>();
202#endif
203#if ENABLE(BATTERY_STATUS)
204    addSupplement<WebBatteryManager>();
205#endif
206#if USE(SOUP) && !ENABLE(CUSTOM_PROTOCOLS)
207    addSupplement<WebSoupRequestManager>();
208#endif
209    m_plugInAutoStartOriginHashes.add(SessionID::defaultSessionID(), HashMap<unsigned, double>());
210}
211
212void WebProcess::initializeProcess(const ChildProcessInitializationParameters& parameters)
213{
214    platformInitializeProcess(parameters);
215}
216
217void WebProcess::initializeConnection(IPC::Connection* connection)
218{
219    ChildProcess::initializeConnection(connection);
220
221    connection->setShouldExitOnSyncMessageSendFailure(true);
222
223    m_eventDispatcher->initializeConnection(connection);
224#if PLATFORM(IOS)
225    m_viewUpdateDispatcher->initializeConnection(connection);
226#endif // PLATFORM(IOS)
227
228#if ENABLE(NETSCAPE_PLUGIN_API)
229    m_pluginProcessConnectionManager->initializeConnection(connection);
230#endif
231
232#if ENABLE(SEC_ITEM_SHIM)
233    SecItemShim::shared().initializeConnection(connection);
234#endif
235
236    WebProcessSupplementMap::const_iterator it = m_supplements.begin();
237    WebProcessSupplementMap::const_iterator end = m_supplements.end();
238    for (; it != end; ++it)
239        it->value->initializeConnection(connection);
240
241    m_webConnection = WebConnectionToUIProcess::create(this);
242
243    // In order to ensure that the asynchronous messages that are used for notifying the UI process
244    // about when WebFrame objects come and go are always delivered before the synchronous policy messages,
245    // use this flag to force synchronous messages to be treated as asynchronous messages in the UI process
246    // unless when doing so would lead to a deadlock.
247    connection->setOnlySendMessagesAsDispatchWhenWaitingForSyncReplyWhenProcessingSuchAMessage(true);
248}
249
250void WebProcess::didCreateDownload()
251{
252    disableTermination();
253}
254
255void WebProcess::didDestroyDownload()
256{
257    enableTermination();
258}
259
260IPC::Connection* WebProcess::downloadProxyConnection()
261{
262    return parentProcessConnection();
263}
264
265AuthenticationManager& WebProcess::downloadsAuthenticationManager()
266{
267    return *supplement<AuthenticationManager>();
268}
269
270void WebProcess::initializeWebProcess(const WebProcessCreationParameters& parameters, IPC::MessageDecoder& decoder)
271{
272    ASSERT(m_pageMap.isEmpty());
273
274    platformInitializeWebProcess(parameters, decoder);
275
276    WTF::setCurrentThreadIsUserInitiated();
277
278    memoryPressureHandler().install();
279
280    RefPtr<API::Object> injectedBundleInitializationUserData;
281    InjectedBundleUserMessageDecoder messageDecoder(injectedBundleInitializationUserData);
282    if (!decoder.decode(messageDecoder))
283        return;
284
285    if (!parameters.injectedBundlePath.isEmpty())
286        m_injectedBundle = InjectedBundle::create(parameters, injectedBundleInitializationUserData.get());
287
288    WebProcessSupplementMap::const_iterator it = m_supplements.begin();
289    WebProcessSupplementMap::const_iterator end = m_supplements.end();
290    for (; it != end; ++it)
291        it->value->initialize(parameters);
292
293#if ENABLE(ICONDATABASE)
294    m_iconDatabaseProxy->setEnabled(parameters.iconDatabaseEnabled);
295#endif
296
297    if (!parameters.applicationCacheDirectory.isEmpty())
298        cacheStorage().setCacheDirectory(parameters.applicationCacheDirectory);
299
300    setCacheModel(static_cast<uint32_t>(parameters.cacheModel));
301
302    if (!parameters.languages.isEmpty())
303        overrideUserPreferredLanguages(parameters.languages);
304
305    m_textCheckerState = parameters.textCheckerState;
306
307    m_fullKeyboardAccessEnabled = parameters.fullKeyboardAccessEnabled;
308
309    for (size_t i = 0; i < parameters.urlSchemesRegistererdAsEmptyDocument.size(); ++i)
310        registerURLSchemeAsEmptyDocument(parameters.urlSchemesRegistererdAsEmptyDocument[i]);
311
312    for (size_t i = 0; i < parameters.urlSchemesRegisteredAsSecure.size(); ++i)
313        registerURLSchemeAsSecure(parameters.urlSchemesRegisteredAsSecure[i]);
314
315    for (size_t i = 0; i < parameters.urlSchemesForWhichDomainRelaxationIsForbidden.size(); ++i)
316        setDomainRelaxationForbiddenForURLScheme(parameters.urlSchemesForWhichDomainRelaxationIsForbidden[i]);
317
318    for (size_t i = 0; i < parameters.urlSchemesRegisteredAsLocal.size(); ++i)
319        registerURLSchemeAsLocal(parameters.urlSchemesRegisteredAsLocal[i]);
320
321    for (size_t i = 0; i < parameters.urlSchemesRegisteredAsNoAccess.size(); ++i)
322        registerURLSchemeAsNoAccess(parameters.urlSchemesRegisteredAsNoAccess[i]);
323
324    for (size_t i = 0; i < parameters.urlSchemesRegisteredAsDisplayIsolated.size(); ++i)
325        registerURLSchemeAsDisplayIsolated(parameters.urlSchemesRegisteredAsDisplayIsolated[i]);
326
327    for (size_t i = 0; i < parameters.urlSchemesRegisteredAsCORSEnabled.size(); ++i)
328        registerURLSchemeAsCORSEnabled(parameters.urlSchemesRegisteredAsCORSEnabled[i]);
329
330#if ENABLE(CACHE_PARTITIONING)
331    for (auto& scheme : parameters.urlSchemesRegisteredAsCachePartitioned)
332        registerURLSchemeAsCachePartitioned(scheme);
333#endif
334
335    setDefaultRequestTimeoutInterval(parameters.defaultRequestTimeoutInterval);
336
337    if (parameters.shouldAlwaysUseComplexTextCodePath)
338        setAlwaysUsesComplexTextCodePath(true);
339
340    if (parameters.shouldUseFontSmoothing)
341        setShouldUseFontSmoothing(true);
342
343#if PLATFORM(COCOA) || USE(CFNETWORK)
344    SessionTracker::setIdentifierBase(parameters.uiProcessBundleIdentifier);
345#endif
346
347    if (parameters.shouldUseTestingNetworkSession)
348        NetworkStorageSession::switchToNewTestingSession();
349
350#if ENABLE(NETWORK_PROCESS)
351    m_usesNetworkProcess = parameters.usesNetworkProcess;
352    ensureNetworkProcessConnection();
353
354#if PLATFORM(COCOA)
355    if (usesNetworkProcess())
356        CookieStorageShim::shared().initialize();
357#endif
358#endif
359    setTerminationTimeout(parameters.terminationTimeout);
360
361    resetPlugInAutoStartOriginHashes(parameters.plugInAutoStartOriginHashes);
362    for (size_t i = 0; i < parameters.plugInAutoStartOrigins.size(); ++i)
363        m_plugInAutoStartOrigins.add(parameters.plugInAutoStartOrigins[i]);
364
365    setMemoryCacheDisabled(parameters.memoryCacheDisabled);
366
367#if ENABLE(SERVICE_CONTROLS)
368    setEnabledServices(parameters.hasImageServices, parameters.hasSelectionServices, parameters.hasRichContentServices);
369#endif
370
371#if ENABLE(REMOTE_INSPECTOR)
372    audit_token_t auditToken;
373    if (parentProcessConnection()->getAuditToken(auditToken)) {
374        RetainPtr<CFDataRef> auditData = adoptCF(CFDataCreate(nullptr, (const UInt8*)&auditToken, sizeof(auditToken)));
375        Inspector::RemoteInspector::shared().setParentProcessInformation(presenterApplicationPid(), auditData);
376    }
377#endif
378}
379
380#if ENABLE(NETWORK_PROCESS)
381void WebProcess::ensureNetworkProcessConnection()
382{
383    if (!m_usesNetworkProcess)
384        return;
385
386    if (m_networkProcessConnection)
387        return;
388
389    IPC::Attachment encodedConnectionIdentifier;
390
391    if (!parentProcessConnection()->sendSync(Messages::WebProcessProxy::GetNetworkProcessConnection(),
392        Messages::WebProcessProxy::GetNetworkProcessConnection::Reply(encodedConnectionIdentifier), 0))
393        return;
394
395#if OS(DARWIN)
396    IPC::Connection::Identifier connectionIdentifier(encodedConnectionIdentifier.port());
397#elif USE(UNIX_DOMAIN_SOCKETS)
398    IPC::Connection::Identifier connectionIdentifier = encodedConnectionIdentifier.releaseFileDescriptor();
399#else
400    ASSERT_NOT_REACHED();
401#endif
402    if (IPC::Connection::identifierIsNull(connectionIdentifier))
403        return;
404    m_networkProcessConnection = NetworkProcessConnection::create(connectionIdentifier);
405}
406#endif // ENABLE(NETWORK_PROCESS)
407
408void WebProcess::registerURLSchemeAsEmptyDocument(const String& urlScheme)
409{
410    SchemeRegistry::registerURLSchemeAsEmptyDocument(urlScheme);
411}
412
413void WebProcess::registerURLSchemeAsSecure(const String& urlScheme) const
414{
415    SchemeRegistry::registerURLSchemeAsSecure(urlScheme);
416}
417
418void WebProcess::setDomainRelaxationForbiddenForURLScheme(const String& urlScheme) const
419{
420    SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(true, urlScheme);
421}
422
423void WebProcess::registerURLSchemeAsLocal(const String& urlScheme) const
424{
425    SchemeRegistry::registerURLSchemeAsLocal(urlScheme);
426}
427
428void WebProcess::registerURLSchemeAsNoAccess(const String& urlScheme) const
429{
430    SchemeRegistry::registerURLSchemeAsNoAccess(urlScheme);
431}
432
433void WebProcess::registerURLSchemeAsDisplayIsolated(const String& urlScheme) const
434{
435    SchemeRegistry::registerURLSchemeAsDisplayIsolated(urlScheme);
436}
437
438void WebProcess::registerURLSchemeAsCORSEnabled(const String& urlScheme) const
439{
440    SchemeRegistry::registerURLSchemeAsCORSEnabled(urlScheme);
441}
442
443#if ENABLE(CACHE_PARTITIONING)
444void WebProcess::registerURLSchemeAsCachePartitioned(const String& urlScheme) const
445{
446    SchemeRegistry::registerURLSchemeAsCachePartitioned(urlScheme);
447}
448#endif
449
450void WebProcess::setDefaultRequestTimeoutInterval(double timeoutInterval)
451{
452    ResourceRequest::setDefaultTimeoutInterval(timeoutInterval);
453}
454
455void WebProcess::setAlwaysUsesComplexTextCodePath(bool alwaysUseComplexText)
456{
457    WebCore::Font::setCodePath(alwaysUseComplexText ? WebCore::Font::Complex : WebCore::Font::Auto);
458}
459
460void WebProcess::setShouldUseFontSmoothing(bool useFontSmoothing)
461{
462    WebCore::Font::setShouldUseSmoothing(useFontSmoothing);
463}
464
465void WebProcess::userPreferredLanguagesChanged(const Vector<String>& languages) const
466{
467    overrideUserPreferredLanguages(languages);
468    languageDidChange();
469}
470
471void WebProcess::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled)
472{
473    m_fullKeyboardAccessEnabled = fullKeyboardAccessEnabled;
474}
475
476void WebProcess::ensurePrivateBrowsingSession(SessionID sessionID)
477{
478#if PLATFORM(COCOA) || USE(CFNETWORK) || USE(SOUP)
479    WebFrameNetworkingContext::ensurePrivateBrowsingSession(sessionID);
480#endif
481}
482
483void WebProcess::destroyPrivateBrowsingSession(SessionID sessionID)
484{
485#if PLATFORM(COCOA) || USE(CFNETWORK) || USE(SOUP)
486    SessionTracker::destroySession(sessionID);
487#endif
488}
489
490DownloadManager& WebProcess::downloadManager()
491{
492    ASSERT(!usesNetworkProcess());
493
494    static NeverDestroyed<DownloadManager> downloadManager(this);
495    return downloadManager;
496}
497
498#if ENABLE(NETSCAPE_PLUGIN_API)
499PluginProcessConnectionManager& WebProcess::pluginProcessConnectionManager()
500{
501    return *m_pluginProcessConnectionManager;
502}
503#endif
504
505void WebProcess::setCacheModel(uint32_t cm)
506{
507    CacheModel cacheModel = static_cast<CacheModel>(cm);
508
509    if (!m_hasSetCacheModel || cacheModel != m_cacheModel) {
510        m_hasSetCacheModel = true;
511        m_cacheModel = cacheModel;
512        platformSetCacheModel(cacheModel);
513    }
514}
515
516WebPage* WebProcess::focusedWebPage() const
517{
518    HashMap<uint64_t, RefPtr<WebPage>>::const_iterator end = m_pageMap.end();
519    for (HashMap<uint64_t, RefPtr<WebPage>>::const_iterator it = m_pageMap.begin(); it != end; ++it) {
520        WebPage* page = (*it).value.get();
521        if (page->windowAndWebPageAreFocused())
522            return page;
523    }
524    return 0;
525}
526
527WebPage* WebProcess::webPage(uint64_t pageID) const
528{
529    return m_pageMap.get(pageID);
530}
531
532void WebProcess::createWebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
533{
534    // It is necessary to check for page existence here since during a window.open() (or targeted
535    // link) the WebPage gets created both in the synchronous handler and through the normal way.
536    HashMap<uint64_t, RefPtr<WebPage>>::AddResult result = m_pageMap.add(pageID, nullptr);
537    if (result.isNewEntry) {
538        ASSERT(!result.iterator->value);
539        result.iterator->value = WebPage::create(pageID, parameters);
540
541        // Balanced by an enableTermination in removeWebPage.
542        disableTermination();
543    } else
544        result.iterator->value->reinitializeWebPage(parameters);
545
546    ASSERT(result.iterator->value);
547}
548
549void WebProcess::removeWebPage(uint64_t pageID)
550{
551    ASSERT(m_pageMap.contains(pageID));
552
553    pageWillLeaveWindow(pageID);
554    m_pageMap.remove(pageID);
555
556    enableTermination();
557}
558
559bool WebProcess::shouldTerminate()
560{
561    ASSERT(m_pageMap.isEmpty());
562    ASSERT(usesNetworkProcess() || !downloadManager().isDownloading());
563
564    // FIXME: the ShouldTerminate message should also send termination parameters, such as any session cookies that need to be preserved.
565    bool shouldTerminate = false;
566    if (parentProcessConnection()->sendSync(Messages::WebProcessProxy::ShouldTerminate(), Messages::WebProcessProxy::ShouldTerminate::Reply(shouldTerminate), 0)
567        && !shouldTerminate)
568        return false;
569
570    return true;
571}
572
573void WebProcess::terminate()
574{
575#ifndef NDEBUG
576    gcController().garbageCollectNow();
577    fontCache().invalidate();
578    memoryCache()->setDisabled(true);
579#endif
580
581    m_webConnection->invalidate();
582    m_webConnection = nullptr;
583
584    platformTerminate();
585
586    ChildProcess::terminate();
587}
588
589void WebProcess::didReceiveSyncMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
590{
591    messageReceiverMap().dispatchSyncMessage(connection, decoder, replyEncoder);
592}
593
594void WebProcess::didReceiveMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder)
595{
596    if (messageReceiverMap().dispatchMessage(connection, decoder))
597        return;
598
599    if (decoder.messageReceiverName() == Messages::WebProcess::messageReceiverName()) {
600        didReceiveWebProcessMessage(connection, decoder);
601        return;
602    }
603
604    if (decoder.messageReceiverName() == Messages::WebPageGroupProxy::messageReceiverName()) {
605        uint64_t pageGroupID = decoder.destinationID();
606        if (!pageGroupID)
607            return;
608
609        WebPageGroupProxy* pageGroupProxy = webPageGroup(pageGroupID);
610        if (!pageGroupProxy)
611            return;
612
613        pageGroupProxy->didReceiveMessage(connection, decoder);
614    }
615}
616
617void WebProcess::didClose(IPC::Connection*)
618{
619#ifndef NDEBUG
620    m_inDidClose = true;
621
622    // Close all the live pages.
623    Vector<RefPtr<WebPage>> pages;
624    copyValuesToVector(m_pageMap, pages);
625    for (size_t i = 0; i < pages.size(); ++i)
626        pages[i]->close();
627    pages.clear();
628
629    gcController().garbageCollectSoon();
630    fontCache().invalidate();
631    memoryCache()->setDisabled(true);
632#endif
633
634    // The UI process closed this connection, shut down.
635    stopRunLoop();
636}
637
638void WebProcess::didReceiveInvalidMessage(IPC::Connection*, IPC::StringReference, IPC::StringReference)
639{
640    // We received an invalid message, but since this is from the UI process (which we trust),
641    // we'll let it slide.
642}
643
644WebFrame* WebProcess::webFrame(uint64_t frameID) const
645{
646    return m_frameMap.get(frameID);
647}
648
649void WebProcess::addWebFrame(uint64_t frameID, WebFrame* frame)
650{
651    m_frameMap.set(frameID, frame);
652}
653
654void WebProcess::removeWebFrame(uint64_t frameID)
655{
656    m_frameMap.remove(frameID);
657
658    // We can end up here after our connection has closed when WebCore's frame life-support timer
659    // fires when the application is shutting down. There's no need (and no way) to update the UI
660    // process in this case.
661    if (!parentProcessConnection())
662        return;
663
664    parentProcessConnection()->send(Messages::WebProcessProxy::DidDestroyFrame(frameID), 0);
665}
666
667WebPageGroupProxy* WebProcess::webPageGroup(PageGroup* pageGroup)
668{
669    for (HashMap<uint64_t, RefPtr<WebPageGroupProxy>>::const_iterator it = m_pageGroupMap.begin(), end = m_pageGroupMap.end(); it != end; ++it) {
670        if (it->value->corePageGroup() == pageGroup)
671            return it->value.get();
672    }
673
674    return 0;
675}
676
677WebPageGroupProxy* WebProcess::webPageGroup(uint64_t pageGroupID)
678{
679    return m_pageGroupMap.get(pageGroupID);
680}
681
682WebPageGroupProxy* WebProcess::webPageGroup(const WebPageGroupData& pageGroupData)
683{
684    auto result = m_pageGroupMap.add(pageGroupData.pageGroupID, nullptr);
685    if (result.isNewEntry) {
686        ASSERT(!result.iterator->value);
687        result.iterator->value = WebPageGroupProxy::create(pageGroupData);
688    }
689
690    return result.iterator->value.get();
691}
692
693void WebProcess::clearResourceCaches(ResourceCachesToClear resourceCachesToClear)
694{
695    platformClearResourceCaches(resourceCachesToClear);
696
697    // Toggling the cache model like this forces the cache to evict all its in-memory resources.
698    // FIXME: We need a better way to do this.
699    CacheModel cacheModel = m_cacheModel;
700    setCacheModel(CacheModelDocumentViewer);
701    setCacheModel(cacheModel);
702
703    memoryCache()->evictResources();
704
705    // Empty the cross-origin preflight cache.
706    CrossOriginPreflightResultCache::shared().empty();
707}
708
709void WebProcess::clearApplicationCache()
710{
711    // Empty the application cache.
712    cacheStorage().empty();
713}
714
715static inline void addCaseFoldedCharacters(StringHasher& hasher, const String& string)
716{
717    if (string.isEmpty())
718        return;
719    if (string.is8Bit()) {
720        hasher.addCharacters<LChar, CaseFoldingHash::foldCase<LChar>>(string.characters8(), string.length());
721        return;
722    }
723    hasher.addCharacters<UChar, CaseFoldingHash::foldCase<UChar>>(string.characters16(), string.length());
724}
725
726static unsigned hashForPlugInOrigin(const String& pageOrigin, const String& pluginOrigin, const String& mimeType)
727{
728    // We want to avoid concatenating the strings and then taking the hash, since that could lead to an expensive conversion.
729    // We also want to avoid using the hash() function in StringImpl or CaseFoldingHash because that masks out bits for the use of flags.
730    StringHasher hasher;
731    addCaseFoldedCharacters(hasher, pageOrigin);
732    hasher.addCharacter(0);
733    addCaseFoldedCharacters(hasher, pluginOrigin);
734    hasher.addCharacter(0);
735    addCaseFoldedCharacters(hasher, mimeType);
736    return hasher.hash();
737}
738
739bool WebProcess::isPlugInAutoStartOriginHash(unsigned plugInOriginHash, SessionID sessionID)
740{
741    HashMap<WebCore::SessionID, HashMap<unsigned, double>>::const_iterator sessionIterator = m_plugInAutoStartOriginHashes.find(sessionID);
742    HashMap<unsigned, double>::const_iterator it;
743    bool contains = false;
744
745    if (sessionIterator != m_plugInAutoStartOriginHashes.end()) {
746        it = sessionIterator->value.find(plugInOriginHash);
747        contains = it != sessionIterator->value.end();
748    }
749    if (!contains) {
750        sessionIterator = m_plugInAutoStartOriginHashes.find(SessionID::defaultSessionID());
751        it = sessionIterator->value.find(plugInOriginHash);
752        if (it == sessionIterator->value.end())
753            return false;
754    }
755    return currentTime() < it->value;
756}
757
758bool WebProcess::shouldPlugInAutoStartFromOrigin(const WebPage* page, const String& pageOrigin, const String& pluginOrigin, const String& mimeType)
759{
760    if (!pluginOrigin.isEmpty() && m_plugInAutoStartOrigins.contains(pluginOrigin))
761        return true;
762
763#ifdef ENABLE_PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC
764    // The plugin wasn't in the general whitelist, so check if it similar to the primary plugin for the page (if we've found one).
765    if (page && page->matchesPrimaryPlugIn(pageOrigin, pluginOrigin, mimeType))
766        return true;
767#else
768    UNUSED_PARAM(page);
769#endif
770
771    // Lastly check against the more explicit hash list.
772    return isPlugInAutoStartOriginHash(hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType), page->sessionID());
773}
774
775void WebProcess::plugInDidStartFromOrigin(const String& pageOrigin, const String& pluginOrigin, const String& mimeType, SessionID sessionID)
776{
777    if (pageOrigin.isEmpty()) {
778        LOG(Plugins, "Not adding empty page origin");
779        return;
780    }
781
782    unsigned plugInOriginHash = hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType);
783    if (isPlugInAutoStartOriginHash(plugInOriginHash, sessionID)) {
784        LOG(Plugins, "Hash %x already exists as auto-start origin (request for %s)", plugInOriginHash, pageOrigin.utf8().data());
785        return;
786    }
787
788    // We might attempt to start another plugin before the didAddPlugInAutoStartOrigin message
789    // comes back from the parent process. Temporarily add this hash to the list with a thirty
790    // second timeout. That way, even if the parent decides not to add it, we'll only be
791    // incorrect for a little while.
792    m_plugInAutoStartOriginHashes.add(sessionID, HashMap<unsigned, double>()).iterator->value.set(plugInOriginHash, currentTime() + 30 * 1000);
793
794    parentProcessConnection()->send(Messages::WebContext::AddPlugInAutoStartOriginHash(pageOrigin, plugInOriginHash, sessionID), 0);
795}
796
797void WebProcess::didAddPlugInAutoStartOriginHash(unsigned plugInOriginHash, double expirationTime, SessionID sessionID)
798{
799    // When called, some web process (which also might be this one) added the origin for auto-starting,
800    // or received user interaction.
801    // Set the bit to avoid having redundantly call into the UI process upon user interaction.
802    m_plugInAutoStartOriginHashes.add(sessionID, HashMap<unsigned, double>()).iterator->value.set(plugInOriginHash, expirationTime);
803}
804
805void WebProcess::resetPlugInAutoStartOriginDefaultHashes(const HashMap<unsigned, double>& hashes)
806{
807    m_plugInAutoStartOriginHashes.clear();
808    m_plugInAutoStartOriginHashes.add(SessionID::defaultSessionID(), HashMap<unsigned, double>()).iterator->value.swap(const_cast<HashMap<unsigned, double>&>(hashes));
809}
810
811void WebProcess::resetPlugInAutoStartOriginHashes(const HashMap<SessionID, HashMap<unsigned, double>>& hashes)
812{
813    m_plugInAutoStartOriginHashes.swap(const_cast<HashMap<SessionID, HashMap<unsigned, double>>&>(hashes));
814}
815
816void WebProcess::plugInDidReceiveUserInteraction(const String& pageOrigin, const String& pluginOrigin, const String& mimeType, SessionID sessionID)
817{
818    if (pageOrigin.isEmpty())
819        return;
820
821    unsigned plugInOriginHash = hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType);
822    if (!plugInOriginHash)
823        return;
824
825    HashMap<WebCore::SessionID, HashMap<unsigned, double>>::const_iterator sessionIterator = m_plugInAutoStartOriginHashes.find(sessionID);
826    HashMap<unsigned, double>::const_iterator it;
827    bool contains = false;
828    if (sessionIterator != m_plugInAutoStartOriginHashes.end()) {
829        it = sessionIterator->value.find(plugInOriginHash);
830        contains = it != sessionIterator->value.end();
831    }
832    if (!contains) {
833        sessionIterator = m_plugInAutoStartOriginHashes.find(SessionID::defaultSessionID());
834        it = sessionIterator->value.find(plugInOriginHash);
835        if (it == sessionIterator->value.end())
836            return;
837    }
838
839    if (it->value - currentTime() > plugInAutoStartExpirationTimeUpdateThreshold)
840        return;
841
842    parentProcessConnection()->send(Messages::WebContext::PlugInDidReceiveUserInteraction(plugInOriginHash, sessionID), 0);
843}
844
845static void fromCountedSetToHashMap(TypeCountSet* countedSet, HashMap<String, uint64_t>& map)
846{
847    TypeCountSet::const_iterator end = countedSet->end();
848    for (TypeCountSet::const_iterator it = countedSet->begin(); it != end; ++it)
849        map.set(it->key, it->value);
850}
851
852static void getWebCoreMemoryCacheStatistics(Vector<HashMap<String, uint64_t>>& result)
853{
854    String imagesString(ASCIILiteral("Images"));
855    String cssString(ASCIILiteral("CSS"));
856    String xslString(ASCIILiteral("XSL"));
857    String javaScriptString(ASCIILiteral("JavaScript"));
858
859    MemoryCache::Statistics memoryCacheStatistics = memoryCache()->getStatistics();
860
861    HashMap<String, uint64_t> counts;
862    counts.set(imagesString, memoryCacheStatistics.images.count);
863    counts.set(cssString, memoryCacheStatistics.cssStyleSheets.count);
864    counts.set(xslString, memoryCacheStatistics.xslStyleSheets.count);
865    counts.set(javaScriptString, memoryCacheStatistics.scripts.count);
866    result.append(counts);
867
868    HashMap<String, uint64_t> sizes;
869    sizes.set(imagesString, memoryCacheStatistics.images.size);
870    sizes.set(cssString, memoryCacheStatistics.cssStyleSheets.size);
871    sizes.set(xslString, memoryCacheStatistics.xslStyleSheets.size);
872    sizes.set(javaScriptString, memoryCacheStatistics.scripts.size);
873    result.append(sizes);
874
875    HashMap<String, uint64_t> liveSizes;
876    liveSizes.set(imagesString, memoryCacheStatistics.images.liveSize);
877    liveSizes.set(cssString, memoryCacheStatistics.cssStyleSheets.liveSize);
878    liveSizes.set(xslString, memoryCacheStatistics.xslStyleSheets.liveSize);
879    liveSizes.set(javaScriptString, memoryCacheStatistics.scripts.liveSize);
880    result.append(liveSizes);
881
882    HashMap<String, uint64_t> decodedSizes;
883    decodedSizes.set(imagesString, memoryCacheStatistics.images.decodedSize);
884    decodedSizes.set(cssString, memoryCacheStatistics.cssStyleSheets.decodedSize);
885    decodedSizes.set(xslString, memoryCacheStatistics.xslStyleSheets.decodedSize);
886    decodedSizes.set(javaScriptString, memoryCacheStatistics.scripts.decodedSize);
887    result.append(decodedSizes);
888
889    HashMap<String, uint64_t> purgeableSizes;
890    purgeableSizes.set(imagesString, memoryCacheStatistics.images.purgeableSize);
891    purgeableSizes.set(cssString, memoryCacheStatistics.cssStyleSheets.purgeableSize);
892    purgeableSizes.set(xslString, memoryCacheStatistics.xslStyleSheets.purgeableSize);
893    purgeableSizes.set(javaScriptString, memoryCacheStatistics.scripts.purgeableSize);
894    result.append(purgeableSizes);
895
896    HashMap<String, uint64_t> purgedSizes;
897    purgedSizes.set(imagesString, memoryCacheStatistics.images.purgedSize);
898    purgedSizes.set(cssString, memoryCacheStatistics.cssStyleSheets.purgedSize);
899    purgedSizes.set(xslString, memoryCacheStatistics.xslStyleSheets.purgedSize);
900    purgedSizes.set(javaScriptString, memoryCacheStatistics.scripts.purgedSize);
901    result.append(purgedSizes);
902}
903
904void WebProcess::getWebCoreStatistics(uint64_t callbackID)
905{
906    StatisticsData data;
907
908    // Gather JavaScript statistics.
909    {
910        JSLockHolder lock(JSDOMWindow::commonVM());
911        data.statisticsNumbers.set(ASCIILiteral("JavaScriptObjectsCount"), JSDOMWindow::commonVM().heap.objectCount());
912        data.statisticsNumbers.set(ASCIILiteral("JavaScriptGlobalObjectsCount"), JSDOMWindow::commonVM().heap.globalObjectCount());
913        data.statisticsNumbers.set(ASCIILiteral("JavaScriptProtectedObjectsCount"), JSDOMWindow::commonVM().heap.protectedObjectCount());
914        data.statisticsNumbers.set(ASCIILiteral("JavaScriptProtectedGlobalObjectsCount"), JSDOMWindow::commonVM().heap.protectedGlobalObjectCount());
915
916        OwnPtr<TypeCountSet> protectedObjectTypeCounts(JSDOMWindow::commonVM().heap.protectedObjectTypeCounts());
917        fromCountedSetToHashMap(protectedObjectTypeCounts.get(), data.javaScriptProtectedObjectTypeCounts);
918
919        OwnPtr<TypeCountSet> objectTypeCounts(JSDOMWindow::commonVM().heap.objectTypeCounts());
920        fromCountedSetToHashMap(objectTypeCounts.get(), data.javaScriptObjectTypeCounts);
921
922        uint64_t javaScriptHeapSize = JSDOMWindow::commonVM().heap.size();
923        data.statisticsNumbers.set(ASCIILiteral("JavaScriptHeapSize"), javaScriptHeapSize);
924        data.statisticsNumbers.set(ASCIILiteral("JavaScriptFreeSize"), JSDOMWindow::commonVM().heap.capacity() - javaScriptHeapSize);
925    }
926
927    WTF::FastMallocStatistics fastMallocStatistics = WTF::fastMallocStatistics();
928    data.statisticsNumbers.set(ASCIILiteral("FastMallocReservedVMBytes"), fastMallocStatistics.reservedVMBytes);
929    data.statisticsNumbers.set(ASCIILiteral("FastMallocCommittedVMBytes"), fastMallocStatistics.committedVMBytes);
930    data.statisticsNumbers.set(ASCIILiteral("FastMallocFreeListBytes"), fastMallocStatistics.freeListBytes);
931
932    // Gather icon statistics.
933    data.statisticsNumbers.set(ASCIILiteral("IconPageURLMappingCount"), iconDatabase().pageURLMappingCount());
934    data.statisticsNumbers.set(ASCIILiteral("IconRetainedPageURLCount"), iconDatabase().retainedPageURLCount());
935    data.statisticsNumbers.set(ASCIILiteral("IconRecordCount"), iconDatabase().iconRecordCount());
936    data.statisticsNumbers.set(ASCIILiteral("IconsWithDataCount"), iconDatabase().iconRecordCountWithData());
937
938    // Gather font statistics.
939    data.statisticsNumbers.set(ASCIILiteral("CachedFontDataCount"), fontCache().fontDataCount());
940    data.statisticsNumbers.set(ASCIILiteral("CachedFontDataInactiveCount"), fontCache().inactiveFontDataCount());
941
942    // Gather glyph page statistics.
943    data.statisticsNumbers.set(ASCIILiteral("GlyphPageCount"), GlyphPageTreeNode::treeGlyphPageCount());
944
945    // Get WebCore memory cache statistics
946    getWebCoreMemoryCacheStatistics(data.webCoreCacheStatistics);
947
948    parentProcessConnection()->send(Messages::WebContext::DidGetStatistics(data, callbackID), 0);
949}
950
951void WebProcess::garbageCollectJavaScriptObjects()
952{
953    gcController().garbageCollectNow();
954}
955
956void WebProcess::setJavaScriptGarbageCollectorTimerEnabled(bool flag)
957{
958    gcController().setJavaScriptGarbageCollectorTimerEnabled(flag);
959}
960
961void WebProcess::postInjectedBundleMessage(const IPC::DataReference& messageData)
962{
963    InjectedBundle* injectedBundle = WebProcess::shared().injectedBundle();
964    if (!injectedBundle)
965        return;
966
967    IPC::ArgumentDecoder decoder(messageData.data(), messageData.size());
968
969    String messageName;
970    if (!decoder.decode(messageName))
971        return;
972
973    RefPtr<API::Object> messageBody;
974    InjectedBundleUserMessageDecoder messageBodyDecoder(messageBody);
975    if (!decoder.decode(messageBodyDecoder))
976        return;
977
978    injectedBundle->didReceiveMessage(messageName, messageBody.get());
979}
980
981void WebProcess::setInjectedBundleParameter(const String& key, const IPC::DataReference& value)
982{
983    InjectedBundle* injectedBundle = WebProcess::shared().injectedBundle();
984    if (!injectedBundle)
985        return;
986
987    injectedBundle->setBundleParameter(key, value);
988}
989
990bool WebProcess::usesNetworkProcess() const
991{
992#if ENABLE(NETWORK_PROCESS)
993    return m_usesNetworkProcess;
994#else
995    return false;
996#endif
997}
998
999#if ENABLE(NETWORK_PROCESS)
1000NetworkProcessConnection* WebProcess::networkConnection()
1001{
1002    ASSERT(m_usesNetworkProcess);
1003
1004    // If we've lost our connection to the network process (e.g. it crashed) try to re-establish it.
1005    if (!m_networkProcessConnection)
1006        ensureNetworkProcessConnection();
1007
1008    // If we failed to re-establish it then we are beyond recovery and should crash.
1009    if (!m_networkProcessConnection)
1010        CRASH();
1011
1012    return m_networkProcessConnection.get();
1013}
1014
1015void WebProcess::networkProcessConnectionClosed(NetworkProcessConnection* connection)
1016{
1017    ASSERT(m_networkProcessConnection);
1018    ASSERT_UNUSED(connection, m_networkProcessConnection == connection);
1019
1020    m_networkProcessConnection = 0;
1021
1022    m_webResourceLoadScheduler->networkProcessCrashed();
1023}
1024
1025WebResourceLoadScheduler& WebProcess::webResourceLoadScheduler()
1026{
1027    return *m_webResourceLoadScheduler;
1028}
1029#endif // ENABLED(NETWORK_PROCESS)
1030
1031#if ENABLE(DATABASE_PROCESS)
1032void WebProcess::webToDatabaseProcessConnectionClosed(WebToDatabaseProcessConnection* connection)
1033{
1034    ASSERT(m_webToDatabaseProcessConnection);
1035    ASSERT(m_webToDatabaseProcessConnection == connection);
1036
1037    m_webToDatabaseProcessConnection = 0;
1038}
1039
1040WebToDatabaseProcessConnection* WebProcess::webToDatabaseProcessConnection()
1041{
1042    if (!m_webToDatabaseProcessConnection)
1043        ensureWebToDatabaseProcessConnection();
1044
1045    return m_webToDatabaseProcessConnection.get();
1046}
1047
1048void WebProcess::ensureWebToDatabaseProcessConnection()
1049{
1050    if (m_webToDatabaseProcessConnection)
1051        return;
1052
1053    IPC::Attachment encodedConnectionIdentifier;
1054
1055    if (!parentProcessConnection()->sendSync(Messages::WebProcessProxy::GetDatabaseProcessConnection(),
1056        Messages::WebProcessProxy::GetDatabaseProcessConnection::Reply(encodedConnectionIdentifier), 0))
1057        return;
1058
1059#if OS(DARWIN)
1060    IPC::Connection::Identifier connectionIdentifier(encodedConnectionIdentifier.port());
1061    if (IPC::Connection::identifierIsNull(connectionIdentifier))
1062        return;
1063#else
1064    ASSERT_NOT_REACHED();
1065#endif
1066    m_webToDatabaseProcessConnection = WebToDatabaseProcessConnection::create(connectionIdentifier);
1067}
1068
1069#endif // ENABLED(DATABASE_PROCESS)
1070
1071void WebProcess::downloadRequest(uint64_t downloadID, uint64_t initiatingPageID, const ResourceRequest& request)
1072{
1073    WebPage* initiatingPage = initiatingPageID ? webPage(initiatingPageID) : 0;
1074
1075    ResourceRequest requestWithOriginalURL = request;
1076    if (initiatingPage)
1077        initiatingPage->mainFrame()->loader().setOriginalURLForDownloadRequest(requestWithOriginalURL);
1078
1079    downloadManager().startDownload(downloadID, requestWithOriginalURL);
1080}
1081
1082void WebProcess::cancelDownload(uint64_t downloadID)
1083{
1084    downloadManager().cancelDownload(downloadID);
1085}
1086
1087void WebProcess::setEnhancedAccessibility(bool flag)
1088{
1089    WebCore::AXObjectCache::setEnhancedUserInterfaceAccessibility(flag);
1090}
1091
1092void WebProcess::startMemorySampler(const SandboxExtension::Handle& sampleLogFileHandle, const String& sampleLogFilePath, const double interval)
1093{
1094#if ENABLE(MEMORY_SAMPLER)
1095    WebMemorySampler::shared()->start(sampleLogFileHandle, sampleLogFilePath, interval);
1096#else
1097    UNUSED_PARAM(sampleLogFileHandle);
1098    UNUSED_PARAM(sampleLogFilePath);
1099    UNUSED_PARAM(interval);
1100#endif
1101}
1102
1103void WebProcess::stopMemorySampler()
1104{
1105#if ENABLE(MEMORY_SAMPLER)
1106    WebMemorySampler::shared()->stop();
1107#endif
1108}
1109
1110void WebProcess::setTextCheckerState(const TextCheckerState& textCheckerState)
1111{
1112    bool continuousSpellCheckingTurnedOff = !textCheckerState.isContinuousSpellCheckingEnabled && m_textCheckerState.isContinuousSpellCheckingEnabled;
1113    bool grammarCheckingTurnedOff = !textCheckerState.isGrammarCheckingEnabled && m_textCheckerState.isGrammarCheckingEnabled;
1114
1115    m_textCheckerState = textCheckerState;
1116
1117    if (!continuousSpellCheckingTurnedOff && !grammarCheckingTurnedOff)
1118        return;
1119
1120    HashMap<uint64_t, RefPtr<WebPage>>::iterator end = m_pageMap.end();
1121    for (HashMap<uint64_t, RefPtr<WebPage>>::iterator it = m_pageMap.begin(); it != end; ++it) {
1122        WebPage* page = (*it).value.get();
1123        if (continuousSpellCheckingTurnedOff)
1124            page->unmarkAllMisspellings();
1125        if (grammarCheckingTurnedOff)
1126            page->unmarkAllBadGrammar();
1127    }
1128}
1129
1130void WebProcess::releasePageCache()
1131{
1132    int savedPageCacheCapacity = pageCache()->capacity();
1133    pageCache()->setCapacity(0);
1134    pageCache()->setCapacity(savedPageCacheCapacity);
1135}
1136
1137#if !PLATFORM(COCOA)
1138void WebProcess::initializeProcessName(const ChildProcessInitializationParameters&)
1139{
1140}
1141
1142void WebProcess::initializeSandbox(const ChildProcessInitializationParameters&, SandboxInitializationParameters&)
1143{
1144}
1145
1146void WebProcess::platformInitializeProcess(const ChildProcessInitializationParameters&)
1147{
1148}
1149
1150void WebProcess::updateActivePages()
1151{
1152}
1153
1154#endif
1155
1156#if PLATFORM(IOS)
1157void WebProcess::resetAllGeolocationPermissions()
1158{
1159    for (auto it = m_pageMap.begin(), end = m_pageMap.end(); it != end; ++it) {
1160        WebPage* page = (*it).value.get();
1161        if (Frame* mainFrame = page->mainFrame())
1162            mainFrame->resetAllGeolocationPermission();
1163    }
1164}
1165#endif
1166
1167void WebProcess::processWillSuspend()
1168{
1169    memoryPressureHandler().releaseMemory(true);
1170
1171    if (!markAllLayersVolatileIfPossible())
1172        m_processSuspensionCleanupTimer.startRepeating(std::chrono::milliseconds(20));
1173    else
1174        parentProcessConnection()->send(Messages::WebProcessProxy::ProcessReadyToSuspend(), 0);
1175}
1176
1177void WebProcess::cancelProcessWillSuspend()
1178{
1179    // If we've already finished cleaning up and sent ProcessReadyToSuspend, we
1180    // shouldn't send DidCancelProcessSuspension; the UI process strictly expects one or the other.
1181    if (!m_processSuspensionCleanupTimer.isActive())
1182        return;
1183
1184    m_processSuspensionCleanupTimer.stop();
1185    parentProcessConnection()->send(Messages::WebProcessProxy::DidCancelProcessSuspension(), 0);
1186}
1187
1188bool WebProcess::markAllLayersVolatileIfPossible()
1189{
1190    bool successfullyMarkedAllLayersVolatile = true;
1191    for (auto& page : m_pageMap.values()) {
1192        if (auto drawingArea = page->drawingArea())
1193            successfullyMarkedAllLayersVolatile &= drawingArea->markLayersVolatileImmediatelyIfPossible();
1194    }
1195
1196    return successfullyMarkedAllLayersVolatile;
1197}
1198
1199void WebProcess::processSuspensionCleanupTimerFired(Timer<WebProcess>* timer)
1200{
1201    if (markAllLayersVolatileIfPossible()) {
1202        parentProcessConnection()->send(Messages::WebProcessProxy::ProcessReadyToSuspend(), 0);
1203        timer->stop();
1204    }
1205}
1206
1207void WebProcess::pageDidEnterWindow(uint64_t pageID)
1208{
1209    m_pagesInWindows.add(pageID);
1210    m_nonVisibleProcessCleanupTimer.stop();
1211}
1212
1213void WebProcess::pageWillLeaveWindow(uint64_t pageID)
1214{
1215    m_pagesInWindows.remove(pageID);
1216
1217    if (m_pagesInWindows.isEmpty() && !m_nonVisibleProcessCleanupTimer.isActive())
1218        m_nonVisibleProcessCleanupTimer.startOneShot(nonVisibleProcessCleanupDelay);
1219}
1220
1221void WebProcess::nonVisibleProcessCleanupTimerFired(Timer<WebProcess>*)
1222{
1223    ASSERT(m_pagesInWindows.isEmpty());
1224    if (!m_pagesInWindows.isEmpty())
1225        return;
1226
1227#if PLATFORM(COCOA)
1228    wkDestroyRenderingResources();
1229#endif
1230}
1231
1232RefPtr<API::Object> WebProcess::apiObjectByConvertingFromHandles(API::Object* object)
1233{
1234    return UserData::transform(object, [this](const API::Object& object) -> RefPtr<API::Object> {
1235        switch (object.type()) {
1236        case API::Object::Type::FrameHandle: {
1237            auto& frameHandle = static_cast<const API::FrameHandle&>(object);
1238
1239            return webFrame(frameHandle.frameID());
1240        }
1241
1242        default:
1243            return nullptr;
1244        }
1245    });
1246}
1247
1248void WebProcess::setMemoryCacheDisabled(bool disabled)
1249{
1250    if (memoryCache()->disabled() != disabled)
1251        memoryCache()->setDisabled(disabled);
1252}
1253
1254#if ENABLE(SERVICE_CONTROLS)
1255void WebProcess::setEnabledServices(bool hasImageServices, bool hasSelectionServices, bool hasRichContentServices)
1256{
1257    m_hasImageServices = hasImageServices;
1258    m_hasSelectionServices = hasSelectionServices;
1259    m_hasRichContentServices = hasRichContentServices;
1260}
1261#endif
1262
1263} // namespace WebKit
1264