Use a Transformer for UserData as well, to avoid always copying arrays and dictionaries
[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 "WebUserContentControllerProxy.h"
41 #include "WebBackForwardListItem.h"
42 #include "WebContext.h"
43 #include "WebInspectorProxy.h"
44 #include "WebNavigationDataStore.h"
45 #include "WebNotificationManagerProxy.h"
46 #include "WebPageGroup.h"
47 #include "WebPageProxy.h"
48 #include "WebPluginSiteDataManager.h"
49 #include "WebProcessMessages.h"
50 #include "WebProcessProxyMessages.h"
51 #include <WebCore/SuddenTermination.h>
52 #include <WebCore/URL.h>
53 #include <stdio.h>
54 #include <wtf/NeverDestroyed.h>
55 #include <wtf/RunLoop.h>
56 #include <wtf/text/CString.h>
57 #include <wtf/text/WTFString.h>
58
59 #if PLATFORM(COCOA)
60 #include "PDFPlugin.h"
61 #endif
62
63 #if ENABLE(SEC_ITEM_SHIM)
64 #include "SecItemShimProxy.h"
65 #endif
66
67 using namespace WebCore;
68
69 #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, connection())
70 #define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(checkURLReceivedFromWebProcess(url), connection())
71
72 namespace WebKit {
73
74 static uint64_t generatePageID()
75 {
76     static uint64_t uniquePageID;
77     return ++uniquePageID;
78 }
79
80 static WebProcessProxy::WebPageProxyMap& globalPageMap()
81 {
82     ASSERT(RunLoop::isMain());
83     static NeverDestroyed<WebProcessProxy::WebPageProxyMap> pageMap;
84     return pageMap;
85 }
86
87 Ref<WebProcessProxy> WebProcessProxy::create(WebContext& context)
88 {
89     return adoptRef(*new WebProcessProxy(context));
90 }
91
92 WebProcessProxy::WebProcessProxy(WebContext& context)
93     : m_responsivenessTimer(this)
94     , m_context(context)
95     , m_mayHaveUniversalFileReadSandboxExtension(false)
96     , m_customProtocolManagerProxy(this, context)
97     , m_numberOfTimesSuddenTerminationWasDisabled(0)
98     , m_throttler(std::make_unique<ProcessThrottler>(this))
99 {
100     connect();
101 }
102
103 WebProcessProxy::~WebProcessProxy()
104 {
105     if (m_webConnection)
106         m_webConnection->invalidate();
107
108     while (m_numberOfTimesSuddenTerminationWasDisabled-- > 0)
109         WebCore::enableSuddenTermination();
110 }
111
112 void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
113 {
114     launchOptions.processType = ProcessLauncher::WebProcess;
115 #if ENABLE(INSPECTOR)
116     if (&m_context.get() == &WebInspectorProxy::inspectorContext())
117         launchOptions.extraInitializationData.add(ASCIILiteral("inspector-process"), ASCIILiteral("1"));
118 #endif
119     platformGetLaunchOptions(launchOptions);
120 }
121
122 void WebProcessProxy::connectionWillOpen(IPC::Connection* connection)
123 {
124     ASSERT(this->connection() == connection);
125
126 #if ENABLE(SEC_ITEM_SHIM)
127     SecItemShimProxy::shared().initializeConnection(connection);
128 #endif
129
130     for (WebPageProxyMap::iterator it = m_pageMap.begin(), end = m_pageMap.end(); it != end; ++it)
131         it->value->connectionWillOpen(connection);
132
133     m_context->processWillOpenConnection(this);
134 }
135
136 void WebProcessProxy::connectionWillClose(IPC::Connection* connection)
137 {
138     ASSERT(this->connection() == connection);
139
140     for (WebPageProxyMap::iterator it = m_pageMap.begin(), end = m_pageMap.end(); it != end; ++it)
141         it->value->connectionWillClose(connection);
142
143     m_context->processWillCloseConnection(this);
144 }
145
146 void WebProcessProxy::disconnect()
147 {
148     clearConnection();
149
150     if (m_webConnection) {
151         m_webConnection->invalidate();
152         m_webConnection = nullptr;
153     }
154
155     m_responsivenessTimer.invalidate();
156     m_tokenForHoldingLockedFiles = nullptr;
157
158     Vector<RefPtr<WebFrameProxy>> frames;
159     copyValuesToVector(m_frameMap, frames);
160
161     for (size_t i = 0, size = frames.size(); i < size; ++i)
162         frames[i]->disconnect();
163     m_frameMap.clear();
164
165     if (m_downloadProxyMap)
166         m_downloadProxyMap->processDidClose();
167
168     for (VisitedLinkProvider* visitedLinkProvider : m_visitedLinkProviders)
169         visitedLinkProvider->removeProcess(*this);
170     m_visitedLinkProviders.clear();
171
172     for (WebUserContentControllerProxy* webUserContentControllerProxy : m_webUserContentControllerProxies)
173         webUserContentControllerProxy->removeProcess(*this);
174     m_webUserContentControllerProxies.clear();
175
176     m_context->disconnectProcess(this);
177 }
178
179 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID)
180 {
181     return globalPageMap().get(pageID);
182 }
183
184 Ref<WebPageProxy> WebProcessProxy::createWebPage(PageClient& pageClient, const WebPageConfiguration& configuration)
185 {
186     uint64_t pageID = generatePageID();
187     Ref<WebPageProxy> webPage = WebPageProxy::create(pageClient, *this, pageID, configuration);
188
189     m_pageMap.set(pageID, webPage.ptr());
190     globalPageMap().set(pageID, webPage.ptr());
191
192     return webPage;
193 }
194
195 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
196 {
197     ASSERT(!m_pageMap.contains(pageID));
198     ASSERT(!globalPageMap().contains(pageID));
199
200     m_pageMap.set(pageID, webPage);
201     globalPageMap().set(pageID, webPage);
202 }
203
204 void WebProcessProxy::removeWebPage(uint64_t pageID)
205 {
206     m_pageMap.remove(pageID);
207     globalPageMap().remove(pageID);
208     
209     Vector<uint64_t> itemIDsToRemove;
210     for (auto& idAndItem : m_backForwardListItemMap) {
211         if (idAndItem.value->pageID() == pageID)
212             itemIDsToRemove.append(idAndItem.key);
213     }
214     for (auto itemID : itemIDsToRemove)
215         m_backForwardListItemMap.remove(itemID);
216
217     // If this was the last WebPage open in that web process, and we have no other reason to keep it alive, let it go.
218     // We only allow this when using a network process, as otherwise the WebProcess needs to preserve its session state.
219     if (!m_context->usesNetworkProcess() || state() == State::Terminated || !canTerminateChildProcess())
220         return;
221
222     abortProcessLaunchIfNeeded();
223
224 #if PLATFORM(IOS)
225     if (state() == State::Running) {
226         // On iOS deploy a watchdog in the UI process, since the content may be suspended.
227         // 30s should be sufficient for any outstanding activity to complete cleanly.
228         connection()->terminateSoon(30);
229     }
230 #endif
231
232     disconnect();
233 }
234
235 void WebProcessProxy::addVisitedLinkProvider(VisitedLinkProvider& provider)
236 {
237     m_visitedLinkProviders.add(&provider);
238     provider.addProcess(*this);
239 }
240
241 void WebProcessProxy::addWebUserContentControllerProxy(WebUserContentControllerProxy& proxy)
242 {
243     m_webUserContentControllerProxies.add(&proxy);
244     proxy.addProcess(*this);
245 }
246
247 void WebProcessProxy::didDestroyVisitedLinkProvider(VisitedLinkProvider& provider)
248 {
249     ASSERT(m_visitedLinkProviders.contains(&provider));
250     m_visitedLinkProviders.remove(&provider);
251 }
252
253 void WebProcessProxy::didDestroyWebUserContentControllerProxy(WebUserContentControllerProxy& proxy)
254 {
255     ASSERT(m_webUserContentControllerProxies.contains(&proxy));
256     m_webUserContentControllerProxies.remove(&proxy);
257 }
258
259 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
260 {
261     return m_backForwardListItemMap.get(itemID);
262 }
263
264 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item)
265 {
266     // This item was just created by the UIProcess and is being added to the map for the first time
267     // so we should not already have an item for this ID.
268     ASSERT(!m_backForwardListItemMap.contains(item->itemID()));
269
270     m_backForwardListItemMap.set(item->itemID(), item);
271 }
272
273 void WebProcessProxy::assumeReadAccessToBaseURL(const String& urlString)
274 {
275     URL url(URL(), urlString);
276     if (!url.isLocalFile())
277         return;
278
279     // There's a chance that urlString does not point to a directory.
280     // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
281     URL baseURL(URL(), url.baseAsString());
282     
283     // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
284     // to have read access to this directory already.
285     m_localPathsWithAssumedReadAccess.add(baseURL.fileSystemPath());
286 }
287
288 bool WebProcessProxy::hasAssumedReadAccessToURL(const URL& url) const
289 {
290     if (!url.isLocalFile())
291         return false;
292
293     String path = url.fileSystemPath();
294     for (const String& assumedAccessPath : m_localPathsWithAssumedReadAccess) {
295         // There are no ".." components, because URL removes those.
296         if (path.startsWith(assumedAccessPath))
297             return true;
298     }
299
300     return false;
301 }
302
303 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
304 {
305     return checkURLReceivedFromWebProcess(URL(URL(), urlString));
306 }
307
308 bool WebProcessProxy::checkURLReceivedFromWebProcess(const URL& url)
309 {
310     // 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.
311
312     // Any other non-file URL is OK.
313     if (!url.isLocalFile())
314         return true;
315
316     // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
317     if (m_mayHaveUniversalFileReadSandboxExtension)
318         return true;
319
320     // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
321     if (hasAssumedReadAccessToURL(url))
322         return true;
323
324     // Items in back/forward list have been already checked.
325     // 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.
326     String path = url.fileSystemPath();
327     for (WebBackForwardListItemMap::iterator iter = m_backForwardListItemMap.begin(), end = m_backForwardListItemMap.end(); iter != end; ++iter) {
328         if (URL(URL(), iter->value->url()).fileSystemPath() == path)
329             return true;
330         if (URL(URL(), iter->value->originalURL()).fileSystemPath() == path)
331             return true;
332     }
333
334     // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
335     WTFLogAlways("Received an unexpected URL from the web process: '%s'\n", url.string().utf8().data());
336     return false;
337 }
338
339 #if !PLATFORM(COCOA)
340 bool WebProcessProxy::fullKeyboardAccessEnabled()
341 {
342     return false;
343 }
344 #endif
345
346 void WebProcessProxy::addBackForwardItem(uint64_t itemID, uint64_t pageID, const PageState& pageState)
347 {
348     MESSAGE_CHECK_URL(pageState.mainFrameState.originalURLString);
349     MESSAGE_CHECK_URL(pageState.mainFrameState.urlString);
350
351     auto& backForwardListItem = m_backForwardListItemMap.add(itemID, nullptr).iterator->value;
352     if (!backForwardListItem) {
353         BackForwardListItemState backForwardListItemState;
354         backForwardListItemState.identifier = itemID;
355         backForwardListItemState.pageState = pageState;
356         backForwardListItem = WebBackForwardListItem::create(WTF::move(backForwardListItemState), pageID);
357         return;
358     }
359
360     // Update existing item.
361     backForwardListItem->setPageState(pageState);
362 }
363
364 #if ENABLE(NETSCAPE_PLUGIN_API)
365 void WebProcessProxy::getPlugins(bool refresh, Vector<PluginInfo>& plugins, Vector<PluginInfo>& applicationPlugins)
366 {
367     if (refresh)
368         m_context->pluginInfoStore().refresh();
369
370     Vector<PluginModuleInfo> pluginModules = m_context->pluginInfoStore().plugins();
371     for (size_t i = 0; i < pluginModules.size(); ++i)
372         plugins.append(pluginModules[i].info);
373
374 #if ENABLE(PDFKIT_PLUGIN)
375     // Add built-in PDF last, so that it's not used when a real plug-in is installed.
376     if (!m_context->omitPDFSupport()) {
377         plugins.append(PDFPlugin::pluginInfo());
378         applicationPlugins.append(PDFPlugin::pluginInfo());
379     }
380 #else
381     UNUSED_PARAM(applicationPlugins);
382 #endif
383 }
384 #endif // ENABLE(NETSCAPE_PLUGIN_API)
385
386 #if ENABLE(NETSCAPE_PLUGIN_API)
387 void WebProcessProxy::getPluginProcessConnection(uint64_t pluginProcessToken, PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
388 {
389     PluginProcessManager::shared().getPluginProcessConnection(pluginProcessToken, reply);
390 }
391 #endif
392
393 #if ENABLE(NETWORK_PROCESS)
394 void WebProcessProxy::getNetworkProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply> reply)
395 {
396     m_context->getNetworkProcessConnection(reply);
397 }
398 #endif // ENABLE(NETWORK_PROCESS)
399
400 #if ENABLE(DATABASE_PROCESS)
401 void WebProcessProxy::getDatabaseProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetDatabaseProcessConnection::DelayedReply> reply)
402 {
403     m_context->getDatabaseProcessConnection(reply);
404 }
405 #endif // ENABLE(DATABASE_PROCESS)
406
407 void WebProcessProxy::didReceiveMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder)
408 {
409     if (dispatchMessage(connection, decoder))
410         return;
411
412     if (m_context->dispatchMessage(connection, decoder))
413         return;
414
415     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
416         didReceiveWebProcessProxyMessage(connection, decoder);
417         return;
418     }
419
420     // FIXME: Add unhandled message logging.
421 }
422
423 void WebProcessProxy::didReceiveSyncMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
424 {
425     if (dispatchSyncMessage(connection, decoder, replyEncoder))
426         return;
427
428     if (m_context->dispatchSyncMessage(connection, decoder, replyEncoder))
429         return;
430
431     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
432         didReceiveSyncWebProcessProxyMessage(connection, decoder, replyEncoder);
433         return;
434     }
435
436     // FIXME: Add unhandled message logging.
437 }
438
439 void WebProcessProxy::didClose(IPC::Connection*)
440 {
441     // Protect ourselves, as the call to disconnect() below may otherwise cause us
442     // to be deleted before we can finish our work.
443     Ref<WebProcessProxy> protect(*this);
444
445     webConnection()->didClose();
446
447     Vector<RefPtr<WebPageProxy>> pages;
448     copyValuesToVector(m_pageMap, pages);
449
450     disconnect();
451
452     for (size_t i = 0, size = pages.size(); i < size; ++i)
453         pages[i]->processDidCrash();
454
455 }
456
457 void WebProcessProxy::didReceiveInvalidMessage(IPC::Connection* connection, IPC::StringReference messageReceiverName, IPC::StringReference messageName)
458 {
459     WTFLogAlways("Received an invalid message \"%s.%s\" from the web process.\n", messageReceiverName.toString().data(), messageName.toString().data());
460
461     WebContext::didReceiveInvalidMessage(messageReceiverName, messageName);
462
463     // Terminate the WebProcess.
464     terminate();
465
466     // Since we've invalidated the connection we'll never get a IPC::Connection::Client::didClose
467     // callback so we'll explicitly call it here instead.
468     didClose(connection);
469 }
470
471 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*)
472 {
473     Vector<RefPtr<WebPageProxy>> pages;
474     copyValuesToVector(m_pageMap, pages);
475     for (size_t i = 0, size = pages.size(); i < size; ++i)
476         pages[i]->processDidBecomeUnresponsive();
477 }
478
479 void WebProcessProxy::interactionOccurredWhileUnresponsive(ResponsivenessTimer*)
480 {
481     Vector<RefPtr<WebPageProxy>> pages;
482     copyValuesToVector(m_pageMap, pages);
483     for (size_t i = 0, size = pages.size(); i < size; ++i)
484         pages[i]->interactionOccurredWhileProcessUnresponsive();
485 }
486
487 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*)
488 {
489     Vector<RefPtr<WebPageProxy>> pages;
490     copyValuesToVector(m_pageMap, pages);
491     for (size_t i = 0, size = pages.size(); i < size; ++i)
492         pages[i]->processDidBecomeResponsive();
493 }
494
495 void WebProcessProxy::didFinishLaunching(ProcessLauncher* launcher, IPC::Connection::Identifier connectionIdentifier)
496 {
497     ChildProcessProxy::didFinishLaunching(launcher, connectionIdentifier);
498
499     for (WebPageProxy* page : m_pageMap.values()) {
500         ASSERT(this == &page->process());
501         page->processDidFinishLaunching();
502     }
503
504     m_webConnection = WebConnectionToWebProcess::create(this);
505
506     m_context->processDidFinishLaunching(this);
507
508 #if PLATFORM(IOS) && USE(XPC_SERVICES)
509     xpc_connection_t xpcConnection = connection()->xpcConnection();
510     ASSERT(xpcConnection);
511     m_throttler->didConnnectToProcess(xpc_connection_get_pid(xpcConnection));
512 #endif
513 }
514
515 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
516 {
517     if (!WebFrameProxyMap::isValidKey(frameID))
518         return 0;
519
520     return m_frameMap.get(frameID);
521 }
522
523 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
524 {
525     return WebFrameProxyMap::isValidKey(frameID) && !m_frameMap.contains(frameID);
526 }
527
528 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
529 {
530     ASSERT(canCreateFrame(frameID));
531     m_frameMap.set(frameID, frameProxy);
532 }
533
534 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
535 {
536     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
537     // back to the UIProcess, then the frameDestroyed message will still be received because it
538     // gets sent directly to the WebProcessProxy.
539     ASSERT(WebFrameProxyMap::isValidKey(frameID));
540     m_frameMap.remove(frameID);
541 }
542
543 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
544 {
545     Vector<RefPtr<WebFrameProxy>> frames;
546     copyValuesToVector(m_frameMap, frames);
547     for (size_t i = 0, size = frames.size(); i < size; ++i) {
548         if (frames[i]->page() == page)
549             frames[i]->disconnect();
550     }
551 }
552
553 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
554 {
555     size_t result = 0;
556     for (HashMap<uint64_t, RefPtr<WebFrameProxy>>::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
557         if (iter->value->page() == page)
558             ++result;
559     }
560     return result;
561 }
562
563 bool WebProcessProxy::canTerminateChildProcess()
564 {
565     if (!m_pageMap.isEmpty())
566         return false;
567
568     if (m_downloadProxyMap && !m_downloadProxyMap->isEmpty())
569         return false;
570
571     if (!m_context->shouldTerminate(this))
572         return false;
573
574     return true;
575 }
576
577 void WebProcessProxy::shouldTerminate(bool& shouldTerminate)
578 {
579     shouldTerminate = canTerminateChildProcess();
580     if (shouldTerminate) {
581         // We know that the web process is going to terminate so disconnect it from the context.
582         disconnect();
583     }
584 }
585
586 void WebProcessProxy::updateTextCheckerState()
587 {
588     if (canSendMessage())
589         send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
590 }
591
592 DownloadProxy* WebProcessProxy::createDownloadProxy(const ResourceRequest& request)
593 {
594 #if ENABLE(NETWORK_PROCESS)
595     ASSERT(!m_context->usesNetworkProcess());
596 #endif
597
598     if (!m_downloadProxyMap)
599         m_downloadProxyMap = std::make_unique<DownloadProxyMap>(this);
600
601     return m_downloadProxyMap->createDownloadProxy(m_context, request);
602 }
603
604 void WebProcessProxy::didSaveToPageCache()
605 {
606     m_context->processDidCachePage(this);
607 }
608
609 void WebProcessProxy::releasePageCache()
610 {
611     if (canSendMessage())
612         send(Messages::WebProcess::ReleasePageCache(), 0);
613 }
614
615 void WebProcessProxy::windowServerConnectionStateChanged()
616 {
617     for (const auto& page : m_pageMap.values())
618         page->viewStateDidChange(ViewState::IsVisuallyIdle);
619 }
620
621 void WebProcessProxy::requestTermination()
622 {
623     if (state() != State::Running)
624         return;
625
626     ChildProcessProxy::terminate();
627
628     if (webConnection())
629         webConnection()->didClose();
630
631     disconnect();
632 }
633
634 void WebProcessProxy::enableSuddenTermination()
635 {
636     if (state() != State::Running)
637         return;
638
639     ASSERT(m_numberOfTimesSuddenTerminationWasDisabled);
640     WebCore::enableSuddenTermination();
641     --m_numberOfTimesSuddenTerminationWasDisabled;
642 }
643
644 void WebProcessProxy::disableSuddenTermination()
645 {
646     if (state() != State::Running)
647         return;
648
649     WebCore::disableSuddenTermination();
650     ++m_numberOfTimesSuddenTerminationWasDisabled;
651 }
652
653 RefPtr<API::Object> WebProcessProxy::apiObjectByConvertingToHandles(API::Object* object)
654 {
655     struct Transformer : UserData::Transformer {
656         virtual bool shouldTransformObjectOfType(API::Object::Type type) const
657         {
658             switch (type) {
659             case API::Object::Type::Frame:
660             case API::Object::Type::Page:
661             case API::Object::Type::PageGroup:
662                 return true;
663
664             default:
665                 return false;
666             }
667         }
668
669         virtual RefPtr<API::Object> transformObject(API::Object& object) const override
670         {
671             switch (object.type()) {
672             case API::Object::Type::Frame: {
673                 auto& frame = static_cast<const WebFrameProxy&>(object);
674                 return API::FrameHandle::create(frame.frameID());
675             }
676
677             case API::Object::Type::Page: {
678                 auto& page = static_cast<const WebPageProxy&>(object);
679                 return API::PageHandle::create(page.pageID());
680             }
681
682             case API::Object::Type::PageGroup: {
683                 auto& pageGroup = static_cast<const WebPageGroup&>(object);
684                 return API::PageGroupHandle::create(WebPageGroupData(pageGroup.data()));
685             }
686
687             default:
688                 return nullptr;
689             }
690         }
691     } transformer;
692
693     return UserData::transform(object, transformer);
694 }
695
696 void WebProcessProxy::sendProcessWillSuspend()
697 {
698     if (canSendMessage())
699         send(Messages::WebProcess::ProcessWillSuspend(), 0);
700 }
701
702 void WebProcessProxy::sendCancelProcessWillSuspend()
703 {
704     if (canSendMessage())
705         send(Messages::WebProcess::CancelProcessWillSuspend(), 0);
706 }
707     
708 void WebProcessProxy::processReadyToSuspend()
709 {
710     m_throttler->processReadyToSuspend();
711 }
712
713 void WebProcessProxy::didCancelProcessSuspension()
714 {
715     m_throttler->didCancelProcessSuspension();
716 }
717
718 void WebProcessProxy::setIsHoldingLockedFiles(bool isHoldingLockedFiles)
719 {
720     if (!isHoldingLockedFiles) {
721         m_tokenForHoldingLockedFiles = nullptr;
722         return;
723     }
724     if (!m_tokenForHoldingLockedFiles)
725         m_tokenForHoldingLockedFiles = m_throttler->backgroundActivityToken();
726 }
727
728 } // namespace WebKit