2 * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "WebProcessProxy.h"
29 #include "DataReference.h"
30 #include "PluginInfoStore.h"
31 #include "PluginProcessManager.h"
32 #include "TextChecker.h"
33 #include "TextCheckerState.h"
34 #include "WebBackForwardListItem.h"
35 #include "WebContext.h"
36 #include "WebNavigationDataStore.h"
37 #include "WebNotificationManagerProxy.h"
38 #include "WebPageProxy.h"
39 #include "WebProcessMessages.h"
40 #include "WebProcessProxyMessages.h"
41 #include <WebCore/KURL.h>
43 #include <wtf/text/CString.h>
44 #include <wtf/text/WTFString.h>
46 using namespace WebCore;
49 #ifdef MESSAGE_CHECK_URL
50 #undef MESSAGE_CHECK_URL
53 #define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(checkURLReceivedFromWebProcess(url), connection())
57 template<typename HashMap>
58 static inline bool isGoodKey(const typename HashMap::KeyType& key)
60 return key != HashTraits<typename HashMap::KeyType>::emptyValue() && !HashTraits<typename HashMap::KeyType>::isDeletedValue(key);
63 static uint64_t generatePageID()
65 static uint64_t uniquePageID = 1;
66 return uniquePageID++;
69 PassRefPtr<WebProcessProxy> WebProcessProxy::create(PassRefPtr<WebContext> context)
71 return adoptRef(new WebProcessProxy(context));
74 WebProcessProxy::WebProcessProxy(PassRefPtr<WebContext> context)
75 : m_responsivenessTimer(this)
77 , m_mayHaveUniversalFileReadSandboxExtension(false)
78 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
79 , m_platformSurfaceTexturePool(adoptPtr(new PlatformSurfaceTexturePool()))
81 #if ENABLE(TIZEN_WEBKIT2_MEMORY_SAVING_MODE)
82 , m_memorySavingModeEnabled(false)
88 WebProcessProxy::~WebProcessProxy()
91 m_connection->invalidate();
93 for (size_t i = 0; i < m_pendingMessages.size(); ++i)
94 m_pendingMessages[i].first.releaseArguments();
96 if (m_processLauncher) {
97 m_processLauncher->invalidate();
98 m_processLauncher = 0;
101 if (m_threadLauncher) {
102 m_threadLauncher->invalidate();
103 m_threadLauncher = 0;
107 void WebProcessProxy::connect()
109 if (m_context->processModel() == ProcessModelSharedSecondaryThread) {
110 ASSERT(!m_threadLauncher);
111 m_threadLauncher = ThreadLauncher::create(this);
113 ASSERT(!m_processLauncher);
115 ProcessLauncher::LaunchOptions launchOptions;
116 launchOptions.processType = ProcessLauncher::WebProcess;
119 // We want the web process to match the architecture of the UI process.
120 launchOptions.architecture = ProcessLauncher::LaunchOptions::MatchCurrentArchitecture;
121 launchOptions.executableHeap = false;
124 const char* webProcessCmdPrefix = getenv("WEB_PROCESS_CMD_PREFIX");
125 if (webProcessCmdPrefix && *webProcessCmdPrefix)
126 launchOptions.processCmdPrefix = String::fromUTF8(webProcessCmdPrefix);
128 m_processLauncher = ProcessLauncher::create(this, launchOptions);
132 void WebProcessProxy::disconnect()
135 m_connection->connection()->removeQueueClient(this);
136 m_connection->invalidate();
137 m_connection = nullptr;
140 m_responsivenessTimer.stop();
142 Vector<RefPtr<WebFrameProxy> > frames;
143 copyValuesToVector(m_frameMap, frames);
145 for (size_t i = 0, size = frames.size(); i < size; ++i)
146 frames[i]->disconnect();
149 m_context->disconnectProcess(this);
152 bool WebProcessProxy::sendMessage(CoreIPC::MessageID messageID, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments, unsigned messageSendFlags)
154 // If we're waiting for the web process to launch, we need to stash away the messages so we can send them once we have
155 // a CoreIPC connection.
157 m_pendingMessages.append(make_pair(CoreIPC::Connection::OutgoingMessage(messageID, arguments), messageSendFlags));
161 // If the web process has exited, m_connection will be null here.
165 return connection()->sendMessage(messageID, arguments, messageSendFlags);
168 bool WebProcessProxy::isLaunching() const
170 if (m_processLauncher)
171 return m_processLauncher->isLaunching();
172 if (m_threadLauncher)
173 return m_threadLauncher->isLaunching();
178 void WebProcessProxy::terminate()
180 if (m_processLauncher)
181 m_processLauncher->terminateProcess();
184 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID) const
186 return m_pageMap.get(pageID);
189 PassRefPtr<WebPageProxy> WebProcessProxy::createWebPage(PageClient* pageClient, WebContext* context, WebPageGroup* pageGroup)
191 ASSERT(context->process() == this);
193 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
194 if (!m_platformSurfaceTexturePool)
195 m_platformSurfaceTexturePool = adoptPtr(new PlatformSurfaceTexturePool());
198 uint64_t pageID = generatePageID();
199 RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageClient, this, pageGroup, pageID);
200 m_pageMap.set(pageID, webPage.get());
201 return webPage.release();
204 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
206 m_pageMap.set(pageID, webPage);
209 void WebProcessProxy::removeWebPage(uint64_t pageID)
211 m_pageMap.remove(pageID);
213 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
214 if (m_pageMap.size() == 0)
215 m_platformSurfaceTexturePool.release();
219 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
221 return m_backForwardListItemMap.get(itemID).get();
224 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item)
226 // This item was just created by the UIProcess and is being added to the map for the first time
227 // so we should not already have an item for this ID.
228 ASSERT(!m_backForwardListItemMap.contains(item->itemID()));
230 m_backForwardListItemMap.set(item->itemID(), item);
233 void WebProcessProxy::assumeReadAccessToBaseURL(const String& urlString)
235 KURL url(KURL(), urlString);
236 if (!url.isLocalFile())
239 // There's a chance that urlString does not point to a directory.
240 // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
241 KURL baseURL(KURL(), url.baseAsString());
243 // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
244 // to have read access to this directory already.
245 m_localPathsWithAssumedReadAccess.add(baseURL.fileSystemPath());
248 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
250 return checkURLReceivedFromWebProcess(KURL(KURL(), urlString));
253 bool WebProcessProxy::checkURLReceivedFromWebProcess(const KURL& url)
255 // 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.
257 // Any other non-file URL is OK.
258 if (!url.isLocalFile())
261 // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
262 if (m_mayHaveUniversalFileReadSandboxExtension)
265 // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
266 // There are no ".." components, because all URLs received from WebProcess are parsed with KURL, which removes those.
267 String path = url.fileSystemPath();
268 for (HashSet<String>::const_iterator iter = m_localPathsWithAssumedReadAccess.begin(); iter != m_localPathsWithAssumedReadAccess.end(); ++iter) {
269 if (path.startsWith(*iter))
273 // Items in back/forward list have been already checked.
274 // 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.
275 for (WebBackForwardListItemMap::iterator iter = m_backForwardListItemMap.begin(), end = m_backForwardListItemMap.end(); iter != end; ++iter) {
276 if (KURL(KURL(), iter->second->url()).fileSystemPath() == path)
278 if (KURL(KURL(), iter->second->originalURL()).fileSystemPath() == path)
282 // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
283 WTFLogAlways("Received an unexpected URL from the web process: '%s'\n", url.string().utf8().data());
288 bool WebProcessProxy::fullKeyboardAccessEnabled()
294 void WebProcessProxy::addBackForwardItem(uint64_t itemID, const String& originalURL, const String& url, const String& title, const CoreIPC::DataReference& backForwardData)
296 MESSAGE_CHECK_URL(originalURL);
297 MESSAGE_CHECK_URL(url);
299 WebBackForwardListItemMap::AddResult result = m_backForwardListItemMap.add(itemID, 0);
300 if (result.isNewEntry) {
301 result.iterator->second = WebBackForwardListItem::create(originalURL, url, title, backForwardData.data(), backForwardData.size(), itemID);
305 // Update existing item.
306 result.iterator->second->setOriginalURL(originalURL);
307 result.iterator->second->setURL(url);
308 result.iterator->second->setTitle(title);
309 result.iterator->second->setBackForwardData(backForwardData.data(), backForwardData.size());
312 #if ENABLE(PLUGIN_PROCESS)
313 void WebProcessProxy::getPluginProcessConnection(const String& pluginPath, PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
315 PluginProcessManager::shared().getPluginProcessConnection(context()->pluginInfoStore(), pluginPath, reply);
318 void WebProcessProxy::pluginSyncMessageSendTimedOut(const String& pluginPath)
320 PluginProcessManager::shared().pluginSyncMessageSendTimedOut(pluginPath);
324 void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
326 if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
327 didReceiveWebProcessProxyMessage(connection, messageID, arguments);
331 if (messageID.is<CoreIPC::MessageClassWebContext>()
332 || messageID.is<CoreIPC::MessageClassWebContextLegacy>()
333 || messageID.is<CoreIPC::MessageClassDownloadProxy>()
334 || messageID.is<CoreIPC::MessageClassWebApplicationCacheManagerProxy>()
335 #if ENABLE(BATTERY_STATUS)
336 || messageID.is<CoreIPC::MessageClassWebBatteryManagerProxy>()
338 || messageID.is<CoreIPC::MessageClassWebCookieManagerProxy>()
339 || messageID.is<CoreIPC::MessageClassWebDatabaseManagerProxy>()
340 || messageID.is<CoreIPC::MessageClassWebGeolocationManagerProxy>()
341 || messageID.is<CoreIPC::MessageClassWebIconDatabase>()
342 || messageID.is<CoreIPC::MessageClassWebKeyValueStorageManagerProxy>()
343 #if ENABLE(TIZEN_FILE_SYSTEM)
344 || messageID.is<CoreIPC::MessageClassWebLocalFileSystemManagerProxy>()
346 || messageID.is<CoreIPC::MessageClassWebMediaCacheManagerProxy>()
347 #if ENABLE(NETWORK_INFO)
348 || messageID.is<CoreIPC::MessageClassWebNetworkInfoManagerProxy>()
350 || messageID.is<CoreIPC::MessageClassWebNotificationManagerProxy>()
352 || messageID.is<CoreIPC::MessageClassWebSoupRequestManagerProxy>()
354 #if ENABLE(VIBRATION)
355 || messageID.is<CoreIPC::MessageClassWebVibrationProxy>()
357 || messageID.is<CoreIPC::MessageClassWebResourceCacheManagerProxy>()) {
358 m_context->didReceiveMessage(connection, messageID, arguments);
362 uint64_t pageID = arguments->destinationID();
366 WebPageProxy* pageProxy = webPage(pageID);
370 pageProxy->didReceiveMessage(connection, messageID, arguments);
373 void WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, OwnPtr<CoreIPC::ArgumentEncoder>& reply)
375 if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
376 didReceiveSyncWebProcessProxyMessage(connection, messageID, arguments, reply);
380 if (messageID.is<CoreIPC::MessageClassWebContext>() || messageID.is<CoreIPC::MessageClassWebContextLegacy>()
381 #if ENABLE(NETWORK_INFO)
382 || messageID.is<CoreIPC::MessageClassWebNetworkInfoManagerProxy>()
384 || messageID.is<CoreIPC::MessageClassDownloadProxy>() || messageID.is<CoreIPC::MessageClassWebIconDatabase>()) {
385 m_context->didReceiveSyncMessage(connection, messageID, arguments, reply);
389 uint64_t pageID = arguments->destinationID();
393 WebPageProxy* pageProxy = webPage(pageID);
397 pageProxy->didReceiveSyncMessage(connection, messageID, arguments, reply);
400 void WebProcessProxy::didReceiveMessageOnConnectionWorkQueue(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, bool& didHandleMessage)
402 if (messageID.is<CoreIPC::MessageClassWebProcessProxy>())
403 didReceiveWebProcessProxyMessageOnConnectionWorkQueue(connection, messageID, arguments, didHandleMessage);
406 void WebProcessProxy::didClose(CoreIPC::Connection*)
408 // Protect ourselves, as the call to disconnect() below may otherwise cause us
409 // to be deleted before we can finish our work.
410 RefPtr<WebProcessProxy> protect(this);
412 Vector<RefPtr<WebPageProxy> > pages;
413 copyValuesToVector(m_pageMap, pages);
417 for (size_t i = 0, size = pages.size(); i < size; ++i)
418 pages[i]->processDidCrash();
421 void WebProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID)
423 WTFLogAlways("Received an invalid message from the web process with message ID %x\n", messageID.toInt());
425 // Terminate the WebProcesses.
429 void WebProcessProxy::syncMessageSendTimedOut(CoreIPC::Connection*)
433 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*)
435 Vector<RefPtr<WebPageProxy> > pages;
436 copyValuesToVector(m_pageMap, pages);
437 for (size_t i = 0, size = pages.size(); i < size; ++i)
438 pages[i]->processDidBecomeUnresponsive();
441 void WebProcessProxy::interactionOccurredWhileUnresponsive(ResponsivenessTimer*)
443 Vector<RefPtr<WebPageProxy> > pages;
444 copyValuesToVector(m_pageMap, pages);
445 for (size_t i = 0, size = pages.size(); i < size; ++i)
446 pages[i]->interactionOccurredWhileProcessUnresponsive();
449 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*)
451 Vector<RefPtr<WebPageProxy> > pages;
452 copyValuesToVector(m_pageMap, pages);
453 for (size_t i = 0, size = pages.size(); i < size; ++i)
454 pages[i]->processDidBecomeResponsive();
457 void WebProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
459 didFinishLaunching(connectionIdentifier);
462 void WebProcessProxy::didFinishLaunching(ThreadLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
464 didFinishLaunching(connectionIdentifier);
467 void WebProcessProxy::didFinishLaunching(CoreIPC::Connection::Identifier connectionIdentifier)
469 ASSERT(!m_connection);
471 m_connection = WebConnectionToWebProcess::create(this, connectionIdentifier, RunLoop::main());
472 m_connection->connection()->addQueueClient(this);
473 m_connection->connection()->open();
475 for (size_t i = 0; i < m_pendingMessages.size(); ++i) {
476 CoreIPC::Connection::OutgoingMessage& outgoingMessage = m_pendingMessages[i].first;
477 unsigned messageSendFlags = m_pendingMessages[i].second;
478 connection()->sendMessage(outgoingMessage.messageID(), adoptPtr(outgoingMessage.arguments()), messageSendFlags);
481 m_pendingMessages.clear();
483 // Tell the context that we finished launching.
484 m_context->processDidFinishLaunching(this);
487 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
489 return isGoodKey<WebFrameProxyMap>(frameID) ? m_frameMap.get(frameID).get() : 0;
492 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
494 return isGoodKey<WebFrameProxyMap>(frameID) && !m_frameMap.contains(frameID);
497 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
499 ASSERT(canCreateFrame(frameID));
500 m_frameMap.set(frameID, frameProxy);
503 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
505 // If the page is closed before it has had the chance to send the DidCreateMainFrame message
506 // back to the UIProcess, then the frameDestroyed message will still be received because it
507 // gets sent directly to the WebProcessProxy.
508 ASSERT(isGoodKey<WebFrameProxyMap>(frameID));
509 m_frameMap.remove(frameID);
512 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
514 Vector<RefPtr<WebFrameProxy> > frames;
515 copyValuesToVector(m_frameMap, frames);
516 for (size_t i = 0, size = frames.size(); i < size; ++i) {
517 if (frames[i]->page() == page)
518 frames[i]->disconnect();
522 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
525 for (HashMap<uint64_t, RefPtr<WebFrameProxy> >::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
526 if (iter->second->page() == page)
532 void WebProcessProxy::shouldTerminate(bool& shouldTerminate)
534 if (!m_pageMap.isEmpty() || !m_context->shouldTerminate(this)) {
535 shouldTerminate = false;
539 shouldTerminate = true;
541 // We know that the web process is going to terminate so disconnect it from the context.
545 void WebProcessProxy::updateTextCheckerState()
547 if (canSendMessage())
548 send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
551 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
552 void WebProcessProxy::removePlatformSurfaceTextureFromPool(int platformSurfaceId)
554 if (m_pageMap.size() > 0)
555 platformSurfaceTexturePool()->removePlatformSurfaceTexture(this, platformSurfaceId);
559 #if ENABLE(TIZEN_WEBKIT2_MEMORY_SAVING_MODE)
560 void WebProcessProxy::setMemorySavingMode(bool mode)
562 m_memorySavingModeEnabled = mode;
566 // FIXME: appropriate settings will be added.
571 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
572 void WebProcessProxy::releaseBackingStoreMemory()
574 Vector<RefPtr<WebPageProxy> > pages;
575 copyValuesToVector(m_pageMap, pages);
576 for (size_t i = 0, size = pages.size(); i < size; ++i)
577 pages[i]->suspendPaintingOfInactiveView();
580 } // namespace WebKit