Track IconDatabase retain counts for WebContent processes. Balance retain/releases...
[WebKit-https.git] / Source / WebKit2 / UIProcess / WebProcessProxy.cpp
1 /*
2  * Copyright (C) 2010, 2011 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 "WebProcessProxy.h"
28
29 #include "APIFrameHandle.h"
30 #include "APIPageGroupHandle.h"
31 #include "APIPageHandle.h"
32 #include "CustomProtocolManagerProxyMessages.h"
33 #include "DataReference.h"
34 #include "DownloadProxyMap.h"
35 #include "PluginInfoStore.h"
36 #include "PluginProcessManager.h"
37 #include "TextChecker.h"
38 #include "TextCheckerState.h"
39 #include "UserData.h"
40 #include "WebBackForwardListItem.h"
41 #include "WebIconDatabase.h"
42 #include "WebInspectorProxy.h"
43 #include "WebNavigationDataStore.h"
44 #include "WebNotificationManagerProxy.h"
45 #include "WebPageGroup.h"
46 #include "WebPageProxy.h"
47 #include "WebPasteboardProxy.h"
48 #include "WebPluginSiteDataManager.h"
49 #include "WebProcessMessages.h"
50 #include "WebProcessPool.h"
51 #include "WebProcessProxyMessages.h"
52 #include "WebUserContentControllerProxy.h"
53 #include "WebsiteData.h"
54 #include <WebCore/SuddenTermination.h>
55 #include <WebCore/URL.h>
56 #include <stdio.h>
57 #include <wtf/NeverDestroyed.h>
58 #include <wtf/RunLoop.h>
59 #include <wtf/text/CString.h>
60 #include <wtf/text/WTFString.h>
61
62 #if PLATFORM(COCOA)
63 #include "ObjCObjectGraph.h"
64 #include "PDFPlugin.h"
65 #endif
66
67 #if ENABLE(SEC_ITEM_SHIM)
68 #include "SecItemShimProxy.h"
69 #endif
70
71 using namespace WebCore;
72
73 #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, connection())
74 #define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(checkURLReceivedFromWebProcess(url), connection())
75
76 namespace WebKit {
77
78 static uint64_t generatePageID()
79 {
80     static uint64_t uniquePageID;
81     return ++uniquePageID;
82 }
83
84 static uint64_t generateCallbackID()
85 {
86     static uint64_t callbackID;
87
88     return ++callbackID;
89 }
90
91 static WebProcessProxy::WebPageProxyMap& globalPageMap()
92 {
93     ASSERT(RunLoop::isMain());
94     static NeverDestroyed<WebProcessProxy::WebPageProxyMap> pageMap;
95     return pageMap;
96 }
97
98 Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool)
99 {
100     return adoptRef(*new WebProcessProxy(processPool));
101 }
102
103 WebProcessProxy::WebProcessProxy(WebProcessPool& processPool)
104     : m_responsivenessTimer(this)
105     , m_processPool(processPool)
106     , m_mayHaveUniversalFileReadSandboxExtension(false)
107     , m_customProtocolManagerProxy(this, processPool)
108     , m_numberOfTimesSuddenTerminationWasDisabled(0)
109     , m_throttler(std::make_unique<ProcessThrottler>(this))
110 {
111     WebPasteboardProxy::singleton().addWebProcessProxy(*this);
112
113     connect();
114 }
115
116 WebProcessProxy::~WebProcessProxy()
117 {
118     ASSERT(m_pendingFetchWebsiteDataCallbacks.isEmpty());
119     ASSERT(m_pendingDeleteWebsiteDataCallbacks.isEmpty());
120     ASSERT(m_pendingDeleteWebsiteDataForOriginsCallbacks.isEmpty());
121     ASSERT(m_pageURLRetainCountMap.isEmpty());
122
123     if (m_webConnection)
124         m_webConnection->invalidate();
125
126     while (m_numberOfTimesSuddenTerminationWasDisabled-- > 0)
127         WebCore::enableSuddenTermination();
128 }
129
130 void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
131 {
132     launchOptions.processType = ProcessLauncher::WebProcess;
133     if (WebInspectorProxy::isInspectorProcessPool(m_processPool))
134         launchOptions.extraInitializationData.add(ASCIILiteral("inspector-process"), ASCIILiteral("1"));
135     platformGetLaunchOptions(launchOptions);
136 }
137
138 void WebProcessProxy::connectionWillOpen(IPC::Connection& connection)
139 {
140     ASSERT(this->connection() == &connection);
141
142 #if ENABLE(SEC_ITEM_SHIM)
143     SecItemShimProxy::singleton().initializeConnection(connection);
144 #endif
145
146     for (auto& page : m_pageMap.values())
147         page->connectionWillOpen(connection);
148 }
149
150 void WebProcessProxy::connectionDidClose(IPC::Connection& connection)
151 {
152     ASSERT(this->connection() == &connection);
153
154     for (const auto& callback : m_pendingFetchWebsiteDataCallbacks.values())
155         callback(WebsiteData());
156     m_pendingFetchWebsiteDataCallbacks.clear();
157
158     for (const auto& callback : m_pendingDeleteWebsiteDataCallbacks.values())
159         callback();
160     m_pendingDeleteWebsiteDataCallbacks.clear();
161
162     for (const auto& callback : m_pendingDeleteWebsiteDataForOriginsCallbacks.values())
163         callback();
164     m_pendingDeleteWebsiteDataForOriginsCallbacks.clear();
165
166     for (auto& page : m_pageMap.values())
167         page->connectionDidClose(connection);
168
169     releaseRemainingIconsForPageURLs();
170 }
171
172 void WebProcessProxy::disconnect()
173 {
174     clearConnection();
175
176     if (m_webConnection) {
177         m_webConnection->invalidate();
178         m_webConnection = nullptr;
179     }
180
181     m_responsivenessTimer.invalidate();
182     m_tokenForHoldingLockedFiles = nullptr;
183
184     Vector<RefPtr<WebFrameProxy>> frames;
185     copyValuesToVector(m_frameMap, frames);
186
187     for (size_t i = 0, size = frames.size(); i < size; ++i)
188         frames[i]->disconnect();
189     m_frameMap.clear();
190
191     if (m_downloadProxyMap)
192         m_downloadProxyMap->processDidClose();
193
194     for (VisitedLinkProvider* visitedLinkProvider : m_visitedLinkProviders)
195         visitedLinkProvider->removeProcess(*this);
196     m_visitedLinkProviders.clear();
197
198     for (WebUserContentControllerProxy* webUserContentControllerProxy : m_webUserContentControllerProxies)
199         webUserContentControllerProxy->removeProcess(*this);
200     m_webUserContentControllerProxies.clear();
201
202     m_processPool->disconnectProcess(this);
203 }
204
205 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID)
206 {
207     return globalPageMap().get(pageID);
208 }
209
210 Ref<WebPageProxy> WebProcessProxy::createWebPage(PageClient& pageClient, const WebPageConfiguration& configuration)
211 {
212     uint64_t pageID = generatePageID();
213     Ref<WebPageProxy> webPage = WebPageProxy::create(pageClient, *this, pageID, configuration);
214
215     m_pageMap.set(pageID, webPage.ptr());
216     globalPageMap().set(pageID, webPage.ptr());
217
218     return webPage;
219 }
220
221 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
222 {
223     ASSERT(!m_pageMap.contains(pageID));
224     ASSERT(!globalPageMap().contains(pageID));
225
226     m_pageMap.set(pageID, webPage);
227     globalPageMap().set(pageID, webPage);
228 }
229
230 void WebProcessProxy::removeWebPage(uint64_t pageID)
231 {
232     m_pageMap.remove(pageID);
233     globalPageMap().remove(pageID);
234     
235     Vector<uint64_t> itemIDsToRemove;
236     for (auto& idAndItem : m_backForwardListItemMap) {
237         if (idAndItem.value->pageID() == pageID)
238             itemIDsToRemove.append(idAndItem.key);
239     }
240     for (auto itemID : itemIDsToRemove)
241         m_backForwardListItemMap.remove(itemID);
242
243     // If this was the last WebPage open in that web process, and we have no other reason to keep it alive, let it go.
244     // We only allow this when using a network process, as otherwise the WebProcess needs to preserve its session state.
245     if (!m_processPool->usesNetworkProcess() || state() == State::Terminated || !canTerminateChildProcess())
246         return;
247
248     abortProcessLaunchIfNeeded();
249
250 #if PLATFORM(IOS)
251     if (state() == State::Running) {
252         // On iOS deploy a watchdog in the UI process, since the content may be suspended.
253         // 30s should be sufficient for any outstanding activity to complete cleanly.
254         connection()->terminateSoon(30);
255     }
256 #endif
257
258     disconnect();
259 }
260
261 void WebProcessProxy::addVisitedLinkProvider(VisitedLinkProvider& provider)
262 {
263     m_visitedLinkProviders.add(&provider);
264     provider.addProcess(*this);
265 }
266
267 void WebProcessProxy::addWebUserContentControllerProxy(WebUserContentControllerProxy& proxy)
268 {
269     m_webUserContentControllerProxies.add(&proxy);
270     proxy.addProcess(*this);
271 }
272
273 void WebProcessProxy::didDestroyVisitedLinkProvider(VisitedLinkProvider& provider)
274 {
275     ASSERT(m_visitedLinkProviders.contains(&provider));
276     m_visitedLinkProviders.remove(&provider);
277 }
278
279 void WebProcessProxy::didDestroyWebUserContentControllerProxy(WebUserContentControllerProxy& proxy)
280 {
281     ASSERT(m_webUserContentControllerProxies.contains(&proxy));
282     m_webUserContentControllerProxies.remove(&proxy);
283 }
284
285 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
286 {
287     return m_backForwardListItemMap.get(itemID);
288 }
289
290 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item)
291 {
292     // This item was just created by the UIProcess and is being added to the map for the first time
293     // so we should not already have an item for this ID.
294     ASSERT(!m_backForwardListItemMap.contains(item->itemID()));
295
296     m_backForwardListItemMap.set(item->itemID(), item);
297 }
298
299 void WebProcessProxy::removeBackForwardItem(uint64_t itemID)
300 {
301     m_backForwardListItemMap.remove(itemID);
302 }
303
304 void WebProcessProxy::assumeReadAccessToBaseURL(const String& urlString)
305 {
306     URL url(URL(), urlString);
307     if (!url.isLocalFile())
308         return;
309
310     // There's a chance that urlString does not point to a directory.
311     // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
312     URL baseURL(URL(), url.baseAsString());
313     
314     // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
315     // to have read access to this directory already.
316     m_localPathsWithAssumedReadAccess.add(baseURL.fileSystemPath());
317 }
318
319 bool WebProcessProxy::hasAssumedReadAccessToURL(const URL& url) const
320 {
321     if (!url.isLocalFile())
322         return false;
323
324     String path = url.fileSystemPath();
325     for (const String& assumedAccessPath : m_localPathsWithAssumedReadAccess) {
326         // There are no ".." components, because URL removes those.
327         if (path.startsWith(assumedAccessPath))
328             return true;
329     }
330
331     return false;
332 }
333
334 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
335 {
336     return checkURLReceivedFromWebProcess(URL(URL(), urlString));
337 }
338
339 bool WebProcessProxy::checkURLReceivedFromWebProcess(const URL& url)
340 {
341     // FIXME: Consider checking that the URL is valid. Currently, WebProcess sends invalid URLs in many cases, but it probably doesn't have good reasons to do that.
342
343     // Any other non-file URL is OK.
344     if (!url.isLocalFile())
345         return true;
346
347     // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
348     if (m_mayHaveUniversalFileReadSandboxExtension)
349         return true;
350
351     // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
352     if (hasAssumedReadAccessToURL(url))
353         return true;
354
355     // Items in back/forward list have been already checked.
356     // One case where we don't have sandbox extensions for file URLs in b/f list is if the list has been reinstated after a crash or a browser restart.
357     String path = url.fileSystemPath();
358     for (WebBackForwardListItemMap::iterator iter = m_backForwardListItemMap.begin(), end = m_backForwardListItemMap.end(); iter != end; ++iter) {
359         URL itemURL(URL(), iter->value->url());
360         if (itemURL.isLocalFile() && itemURL.fileSystemPath() == path)
361             return true;
362         URL itemOriginalURL(URL(), iter->value->originalURL());
363         if (itemOriginalURL.isLocalFile() && itemOriginalURL.fileSystemPath() == path)
364             return true;
365     }
366
367     // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
368     WTFLogAlways("Received an unexpected URL from the web process: '%s'\n", url.string().utf8().data());
369     return false;
370 }
371
372 #if !PLATFORM(COCOA)
373 bool WebProcessProxy::fullKeyboardAccessEnabled()
374 {
375     return false;
376 }
377 #endif
378
379 void WebProcessProxy::addBackForwardItem(uint64_t itemID, uint64_t pageID, const PageState& pageState)
380 {
381     MESSAGE_CHECK_URL(pageState.mainFrameState.originalURLString);
382     MESSAGE_CHECK_URL(pageState.mainFrameState.urlString);
383
384     auto& backForwardListItem = m_backForwardListItemMap.add(itemID, nullptr).iterator->value;
385     if (!backForwardListItem) {
386         BackForwardListItemState backForwardListItemState;
387         backForwardListItemState.identifier = itemID;
388         backForwardListItemState.pageState = pageState;
389         backForwardListItem = WebBackForwardListItem::create(WTF::move(backForwardListItemState), pageID);
390         return;
391     }
392
393     // Update existing item.
394     backForwardListItem->setPageState(pageState);
395 }
396
397 #if ENABLE(NETSCAPE_PLUGIN_API)
398 void WebProcessProxy::getPlugins(bool refresh, Vector<PluginInfo>& plugins, Vector<PluginInfo>& applicationPlugins)
399 {
400     if (refresh)
401         m_processPool->pluginInfoStore().refresh();
402
403     Vector<PluginModuleInfo> pluginModules = m_processPool->pluginInfoStore().plugins();
404     for (size_t i = 0; i < pluginModules.size(); ++i)
405         plugins.append(pluginModules[i].info);
406
407 #if ENABLE(PDFKIT_PLUGIN)
408     // Add built-in PDF last, so that it's not used when a real plug-in is installed.
409     if (!m_processPool->omitPDFSupport()) {
410         plugins.append(PDFPlugin::pluginInfo());
411         applicationPlugins.append(PDFPlugin::pluginInfo());
412     }
413 #else
414     UNUSED_PARAM(applicationPlugins);
415 #endif
416 }
417 #endif // ENABLE(NETSCAPE_PLUGIN_API)
418
419 #if ENABLE(NETSCAPE_PLUGIN_API)
420 void WebProcessProxy::getPluginProcessConnection(uint64_t pluginProcessToken, PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
421 {
422     PluginProcessManager::singleton().getPluginProcessConnection(pluginProcessToken, reply);
423 }
424 #endif
425
426 #if ENABLE(NETWORK_PROCESS)
427 void WebProcessProxy::getNetworkProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply> reply)
428 {
429     m_processPool->getNetworkProcessConnection(reply);
430 }
431 #endif // ENABLE(NETWORK_PROCESS)
432
433 #if ENABLE(DATABASE_PROCESS)
434 void WebProcessProxy::getDatabaseProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetDatabaseProcessConnection::DelayedReply> reply)
435 {
436     m_processPool->getDatabaseProcessConnection(reply);
437 }
438 #endif // ENABLE(DATABASE_PROCESS)
439
440 void WebProcessProxy::retainIconForPageURL(const String& pageURL)
441 {
442     WebIconDatabase* iconDatabase = processPool().iconDatabase();
443     if (!iconDatabase || pageURL.isEmpty())
444         return;
445
446     // Track retain counts so we can release them if the WebProcess terminates early.
447     auto result = m_pageURLRetainCountMap.add(pageURL, 1);
448     if (!result.isNewEntry)
449         ++result.iterator->value;
450
451     iconDatabase->retainIconForPageURL(pageURL);
452 }
453
454 void WebProcessProxy::releaseIconForPageURL(const String& pageURL)
455 {
456     WebIconDatabase* iconDatabase = processPool().iconDatabase();
457     if (!iconDatabase || pageURL.isEmpty())
458         return;
459
460     // Track retain counts so we can release them if the WebProcess terminates early.
461     auto result = m_pageURLRetainCountMap.find(pageURL);
462     if (result == m_pageURLRetainCountMap.end())
463         return;
464
465     --result->value;
466     if (!result->value)
467         m_pageURLRetainCountMap.remove(result);
468
469     iconDatabase->releaseIconForPageURL(pageURL);
470 }
471
472 void WebProcessProxy::releaseRemainingIconsForPageURLs()
473 {
474     WebIconDatabase* iconDatabase = processPool().iconDatabase();
475     if (!iconDatabase)
476         return;
477
478     for (auto iter : m_pageURLRetainCountMap) {
479         uint64_t count = iter.value;
480         for (uint64_t i = 0; i < count; ++i)
481             iconDatabase->releaseIconForPageURL(iter.key);
482     }
483
484     m_pageURLRetainCountMap.clear();
485 }
486
487 void WebProcessProxy::didReceiveMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder)
488 {
489     if (dispatchMessage(connection, decoder))
490         return;
491
492     if (m_processPool->dispatchMessage(connection, decoder))
493         return;
494
495     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
496         didReceiveWebProcessProxyMessage(connection, decoder);
497         return;
498     }
499
500     // FIXME: Add unhandled message logging.
501 }
502
503 void WebProcessProxy::didReceiveSyncMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
504 {
505     if (dispatchSyncMessage(connection, decoder, replyEncoder))
506         return;
507
508     if (m_processPool->dispatchSyncMessage(connection, decoder, replyEncoder))
509         return;
510
511     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
512         didReceiveSyncWebProcessProxyMessage(connection, decoder, replyEncoder);
513         return;
514     }
515
516     // FIXME: Add unhandled message logging.
517 }
518
519 void WebProcessProxy::didClose(IPC::Connection&)
520 {
521     // Protect ourselves, as the call to disconnect() below may otherwise cause us
522     // to be deleted before we can finish our work.
523     Ref<WebProcessProxy> protect(*this);
524
525     webConnection()->didClose();
526
527     Vector<RefPtr<WebPageProxy>> pages;
528     copyValuesToVector(m_pageMap, pages);
529
530     disconnect();
531
532     for (size_t i = 0, size = pages.size(); i < size; ++i)
533         pages[i]->processDidCrash();
534
535 }
536
537 void WebProcessProxy::didReceiveInvalidMessage(IPC::Connection& connection, IPC::StringReference messageReceiverName, IPC::StringReference messageName)
538 {
539     WTFLogAlways("Received an invalid message \"%s.%s\" from the web process.\n", messageReceiverName.toString().data(), messageName.toString().data());
540
541     WebProcessPool::didReceiveInvalidMessage(messageReceiverName, messageName);
542
543     // Terminate the WebProcess.
544     terminate();
545
546     // Since we've invalidated the connection we'll never get a IPC::Connection::Client::didClose
547     // callback so we'll explicitly call it here instead.
548     didClose(connection);
549 }
550
551 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*)
552 {
553     Vector<RefPtr<WebPageProxy>> pages;
554     copyValuesToVector(m_pageMap, pages);
555     for (size_t i = 0, size = pages.size(); i < size; ++i)
556         pages[i]->processDidBecomeUnresponsive();
557 }
558
559 void WebProcessProxy::interactionOccurredWhileUnresponsive(ResponsivenessTimer*)
560 {
561     Vector<RefPtr<WebPageProxy>> pages;
562     copyValuesToVector(m_pageMap, pages);
563     for (size_t i = 0, size = pages.size(); i < size; ++i)
564         pages[i]->interactionOccurredWhileProcessUnresponsive();
565 }
566
567 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*)
568 {
569     Vector<RefPtr<WebPageProxy>> pages;
570     copyValuesToVector(m_pageMap, pages);
571     for (size_t i = 0, size = pages.size(); i < size; ++i)
572         pages[i]->processDidBecomeResponsive();
573 }
574
575 void WebProcessProxy::didFinishLaunching(ProcessLauncher* launcher, IPC::Connection::Identifier connectionIdentifier)
576 {
577     ChildProcessProxy::didFinishLaunching(launcher, connectionIdentifier);
578
579     for (WebPageProxy* page : m_pageMap.values()) {
580         ASSERT(this == &page->process());
581         page->processDidFinishLaunching();
582     }
583
584     m_webConnection = WebConnectionToWebProcess::create(this);
585
586     m_processPool->processDidFinishLaunching(this);
587
588 #if PLATFORM(IOS)
589     xpc_connection_t xpcConnection = connection()->xpcConnection();
590     ASSERT(xpcConnection);
591     m_throttler->didConnectToProcess(xpc_connection_get_pid(xpcConnection));
592 #endif
593
594     initializeNetworkProcessActivityToken();
595 }
596
597 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
598 {
599     if (!WebFrameProxyMap::isValidKey(frameID))
600         return 0;
601
602     return m_frameMap.get(frameID);
603 }
604
605 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
606 {
607     return WebFrameProxyMap::isValidKey(frameID) && !m_frameMap.contains(frameID);
608 }
609
610 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
611 {
612     ASSERT(canCreateFrame(frameID));
613     m_frameMap.set(frameID, frameProxy);
614 }
615
616 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
617 {
618     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
619     // back to the UIProcess, then the frameDestroyed message will still be received because it
620     // gets sent directly to the WebProcessProxy.
621     ASSERT(WebFrameProxyMap::isValidKey(frameID));
622     m_frameMap.remove(frameID);
623 }
624
625 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
626 {
627     Vector<RefPtr<WebFrameProxy>> frames;
628     copyValuesToVector(m_frameMap, frames);
629     for (size_t i = 0, size = frames.size(); i < size; ++i) {
630         if (frames[i]->page() == page)
631             frames[i]->disconnect();
632     }
633 }
634
635 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
636 {
637     size_t result = 0;
638     for (HashMap<uint64_t, RefPtr<WebFrameProxy>>::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
639         if (iter->value->page() == page)
640             ++result;
641     }
642     return result;
643 }
644
645 bool WebProcessProxy::canTerminateChildProcess()
646 {
647     if (!m_pageMap.isEmpty())
648         return false;
649
650     if (m_downloadProxyMap && !m_downloadProxyMap->isEmpty())
651         return false;
652
653     if (!m_pendingDeleteWebsiteDataCallbacks.isEmpty())
654         return false;
655
656     if (!m_processPool->shouldTerminate(this))
657         return false;
658
659     return true;
660 }
661
662 void WebProcessProxy::shouldTerminate(bool& shouldTerminate)
663 {
664     shouldTerminate = canTerminateChildProcess();
665     if (shouldTerminate) {
666         // We know that the web process is going to terminate so disconnect it from the process pool.
667         disconnect();
668     }
669 }
670
671 void WebProcessProxy::didFetchWebsiteData(uint64_t callbackID, const WebsiteData& websiteData)
672 {
673     auto callback = m_pendingFetchWebsiteDataCallbacks.take(callbackID);
674     callback(websiteData);
675 }
676
677 void WebProcessProxy::didDeleteWebsiteData(uint64_t callbackID)
678 {
679     auto callback = m_pendingDeleteWebsiteDataCallbacks.take(callbackID);
680     callback();
681 }
682
683 void WebProcessProxy::didDeleteWebsiteDataForOrigins(uint64_t callbackID)
684 {
685     auto callback = m_pendingDeleteWebsiteDataForOriginsCallbacks.take(callbackID);
686     callback();
687 }
688
689 void WebProcessProxy::updateTextCheckerState()
690 {
691     if (canSendMessage())
692         send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
693 }
694
695 DownloadProxy* WebProcessProxy::createDownloadProxy(const ResourceRequest& request)
696 {
697 #if ENABLE(NETWORK_PROCESS)
698     ASSERT(!m_processPool->usesNetworkProcess());
699 #endif
700
701     if (!m_downloadProxyMap)
702         m_downloadProxyMap = std::make_unique<DownloadProxyMap>(this);
703
704     return m_downloadProxyMap->createDownloadProxy(m_processPool, request);
705 }
706
707 void WebProcessProxy::didSaveToPageCache()
708 {
709     m_processPool->processDidCachePage(this);
710 }
711
712 void WebProcessProxy::releasePageCache()
713 {
714     if (canSendMessage())
715         send(Messages::WebProcess::ReleasePageCache(), 0);
716 }
717
718 void WebProcessProxy::windowServerConnectionStateChanged()
719 {
720     for (const auto& page : m_pageMap.values())
721         page->viewStateDidChange(ViewState::IsVisuallyIdle);
722 }
723
724 void WebProcessProxy::fetchWebsiteData(SessionID sessionID, WebsiteDataTypes dataTypes, std::function<void (WebsiteData)> completionHandler)
725 {
726     ASSERT(canSendMessage());
727
728     uint64_t callbackID = generateCallbackID();
729     m_pendingFetchWebsiteDataCallbacks.add(callbackID, WTF::move(completionHandler));
730
731     send(Messages::WebProcess::FetchWebsiteData(sessionID, dataTypes, callbackID), 0);
732 }
733
734 void WebProcessProxy::deleteWebsiteData(SessionID sessionID, WebsiteDataTypes dataTypes, std::chrono::system_clock::time_point modifiedSince, std::function<void ()> completionHandler)
735 {
736     ASSERT(canSendMessage());
737
738     uint64_t callbackID = generateCallbackID();
739
740     m_pendingDeleteWebsiteDataCallbacks.add(callbackID, WTF::move(completionHandler));
741     send(Messages::WebProcess::DeleteWebsiteData(sessionID, dataTypes, modifiedSince, callbackID), 0);
742 }
743
744 void WebProcessProxy::deleteWebsiteDataForOrigins(SessionID sessionID, WebsiteDataTypes dataTypes, const Vector<RefPtr<WebCore::SecurityOrigin>>& origins, std::function<void ()> completionHandler)
745 {
746     ASSERT(canSendMessage());
747
748     uint64_t callbackID = generateCallbackID();
749     m_pendingDeleteWebsiteDataForOriginsCallbacks.add(callbackID, WTF::move(completionHandler));
750
751     Vector<SecurityOriginData> originData;
752     for (auto& origin : origins)
753         originData.append(SecurityOriginData::fromSecurityOrigin(*origin));
754
755     send(Messages::WebProcess::DeleteWebsiteDataForOrigins(sessionID, dataTypes, originData, callbackID), 0);
756 }
757
758 void WebProcessProxy::requestTermination()
759 {
760     if (state() != State::Running)
761         return;
762
763     ChildProcessProxy::terminate();
764
765     if (webConnection())
766         webConnection()->didClose();
767
768     disconnect();
769 }
770
771 void WebProcessProxy::enableSuddenTermination()
772 {
773     if (state() != State::Running)
774         return;
775
776     ASSERT(m_numberOfTimesSuddenTerminationWasDisabled);
777     WebCore::enableSuddenTermination();
778     --m_numberOfTimesSuddenTerminationWasDisabled;
779 }
780
781 void WebProcessProxy::disableSuddenTermination()
782 {
783     if (state() != State::Running)
784         return;
785
786     WebCore::disableSuddenTermination();
787     ++m_numberOfTimesSuddenTerminationWasDisabled;
788 }
789
790 RefPtr<API::Object> WebProcessProxy::transformHandlesToObjects(API::Object* object)
791 {
792     struct Transformer final : UserData::Transformer {
793         Transformer(WebProcessProxy& webProcessProxy)
794             : m_webProcessProxy(webProcessProxy)
795         {
796         }
797
798         virtual bool shouldTransformObject(const API::Object& object) const override
799         {
800             switch (object.type()) {
801             case API::Object::Type::FrameHandle:
802                 return static_cast<const API::FrameHandle&>(object).isAutoconverting();
803
804             case API::Object::Type::PageHandle:
805                 return static_cast<const API::PageHandle&>(object).isAutoconverting();
806
807             case API::Object::Type::PageGroupHandle:
808 #if PLATFORM(COCOA)
809             case API::Object::Type::ObjCObjectGraph:
810 #endif
811                 return true;
812
813             default:
814                 return false;
815             }
816         }
817
818         virtual RefPtr<API::Object> transformObject(API::Object& object) const override
819         {
820             switch (object.type()) {
821             case API::Object::Type::FrameHandle:
822                 ASSERT(static_cast<API::FrameHandle&>(object).isAutoconverting());
823                 return m_webProcessProxy.webFrame(static_cast<API::FrameHandle&>(object).frameID());
824
825             case API::Object::Type::PageGroupHandle:
826                 return WebPageGroup::get(static_cast<API::PageGroupHandle&>(object).webPageGroupData().pageGroupID);
827
828             case API::Object::Type::PageHandle:
829                 ASSERT(static_cast<API::PageHandle&>(object).isAutoconverting());
830                 return m_webProcessProxy.webPage(static_cast<API::PageHandle&>(object).pageID());
831
832 #if PLATFORM(COCOA)
833             case API::Object::Type::ObjCObjectGraph:
834                 return m_webProcessProxy.transformHandlesToObjects(static_cast<ObjCObjectGraph&>(object));;
835 #endif
836             default:
837                 return &object;
838             }
839         }
840
841         WebProcessProxy& m_webProcessProxy;
842     };
843
844     return UserData::transform(object, Transformer(*this));
845 }
846
847 RefPtr<API::Object> WebProcessProxy::transformObjectsToHandles(API::Object* object)
848 {
849     struct Transformer final : UserData::Transformer {
850         virtual bool shouldTransformObject(const API::Object& object) const override
851         {
852             switch (object.type()) {
853             case API::Object::Type::Frame:
854             case API::Object::Type::Page:
855             case API::Object::Type::PageGroup:
856 #if PLATFORM(COCOA)
857             case API::Object::Type::ObjCObjectGraph:
858 #endif
859                 return true;
860
861             default:
862                 return false;
863             }
864         }
865
866         virtual RefPtr<API::Object> transformObject(API::Object& object) const override
867         {
868             switch (object.type()) {
869             case API::Object::Type::Frame:
870                 return API::FrameHandle::createAutoconverting(static_cast<const WebFrameProxy&>(object).frameID());
871
872             case API::Object::Type::Page:
873                 return API::PageHandle::createAutoconverting(static_cast<const WebPageProxy&>(object).pageID());
874
875             case API::Object::Type::PageGroup:
876                 return API::PageGroupHandle::create(WebPageGroupData(static_cast<const WebPageGroup&>(object).data()));
877
878 #if PLATFORM(COCOA)
879             case API::Object::Type::ObjCObjectGraph:
880                 return transformObjectsToHandles(static_cast<ObjCObjectGraph&>(object));
881 #endif
882
883             default:
884                 return &object;
885             }
886         }
887     };
888
889     return UserData::transform(object, Transformer());
890 }
891
892 void WebProcessProxy::sendProcessWillSuspend()
893 {
894     if (canSendMessage())
895         send(Messages::WebProcess::ProcessWillSuspend(), 0);
896 }
897
898 void WebProcessProxy::sendCancelProcessWillSuspend()
899 {
900     if (canSendMessage())
901         send(Messages::WebProcess::CancelProcessWillSuspend(), 0);
902 }
903
904 void WebProcessProxy::initializeNetworkProcessActivityToken()
905 {
906 #if PLATFORM(IOS) && ENABLE(NETWORK_PROCESS)
907     if (processPool().usesNetworkProcess())
908         m_tokenForNetworkProcess = processPool().ensureNetworkProcess().throttler().foregroundActivityToken();
909 #endif
910 }
911
912 void WebProcessProxy::sendProcessDidResume()
913 {
914     initializeNetworkProcessActivityToken();
915
916     if (canSendMessage())
917         send(Messages::WebProcess::ProcessDidResume(), 0);
918 }
919     
920 void WebProcessProxy::processReadyToSuspend()
921 {
922     m_throttler->processReadyToSuspend();
923 #if PLATFORM(IOS) && ENABLE(NETWORK_PROCESS)
924     m_tokenForNetworkProcess = nullptr;
925 #endif
926 }
927
928 void WebProcessProxy::didCancelProcessSuspension()
929 {
930     m_throttler->didCancelProcessSuspension();
931 }
932
933 void WebProcessProxy::setIsHoldingLockedFiles(bool isHoldingLockedFiles)
934 {
935     if (!isHoldingLockedFiles) {
936         m_tokenForHoldingLockedFiles = nullptr;
937         return;
938     }
939     if (!m_tokenForHoldingLockedFiles)
940         m_tokenForHoldingLockedFiles = m_throttler->backgroundActivityToken();
941 }
942
943 } // namespace WebKit