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 #if ENABLE(TIZEN_PROCESS_PERMISSION_CONTROL)
125 launchOptions.customExecutablePath = m_context->webProcessExecutablePath();
129 const char* webProcessCmdPrefix = getenv("WEB_PROCESS_CMD_PREFIX");
130 if (webProcessCmdPrefix && *webProcessCmdPrefix)
131 launchOptions.processCmdPrefix = String::fromUTF8(webProcessCmdPrefix);
133 m_processLauncher = ProcessLauncher::create(this, launchOptions);
137 void WebProcessProxy::disconnect()
140 m_connection->connection()->removeQueueClient(this);
141 m_connection->invalidate();
142 m_connection = nullptr;
145 m_responsivenessTimer.stop();
147 Vector<RefPtr<WebFrameProxy> > frames;
148 copyValuesToVector(m_frameMap, frames);
150 for (size_t i = 0, size = frames.size(); i < size; ++i)
151 frames[i]->disconnect();
154 m_context->disconnectProcess(this);
157 bool WebProcessProxy::sendMessage(CoreIPC::MessageID messageID, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments, unsigned messageSendFlags)
159 // 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
160 // a CoreIPC connection.
162 m_pendingMessages.append(make_pair(CoreIPC::Connection::OutgoingMessage(messageID, arguments), messageSendFlags));
166 // If the web process has exited, m_connection will be null here.
170 return connection()->sendMessage(messageID, arguments, messageSendFlags);
173 bool WebProcessProxy::isLaunching() const
175 if (m_processLauncher)
176 return m_processLauncher->isLaunching();
177 if (m_threadLauncher)
178 return m_threadLauncher->isLaunching();
183 void WebProcessProxy::terminate()
185 if (m_processLauncher)
186 m_processLauncher->terminateProcess();
189 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID) const
191 return m_pageMap.get(pageID);
194 PassRefPtr<WebPageProxy> WebProcessProxy::createWebPage(PageClient* pageClient, WebContext* context, WebPageGroup* pageGroup)
196 ASSERT(context->process() == this);
198 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
199 if (!m_platformSurfaceTexturePool)
200 m_platformSurfaceTexturePool = adoptPtr(new PlatformSurfaceTexturePool());
203 uint64_t pageID = generatePageID();
204 RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageClient, this, pageGroup, pageID);
205 m_pageMap.set(pageID, webPage.get());
206 return webPage.release();
209 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
211 m_pageMap.set(pageID, webPage);
214 void WebProcessProxy::removeWebPage(uint64_t pageID)
216 m_pageMap.remove(pageID);
218 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
219 if (m_pageMap.size() == 0)
220 m_platformSurfaceTexturePool.release();
224 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
226 return m_backForwardListItemMap.get(itemID).get();
229 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item)
231 // This item was just created by the UIProcess and is being added to the map for the first time
232 // so we should not already have an item for this ID.
233 ASSERT(!m_backForwardListItemMap.contains(item->itemID()));
235 m_backForwardListItemMap.set(item->itemID(), item);
238 void WebProcessProxy::assumeReadAccessToBaseURL(const String& urlString)
240 KURL url(KURL(), urlString);
241 if (!url.isLocalFile())
244 // There's a chance that urlString does not point to a directory.
245 // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
246 KURL baseURL(KURL(), url.baseAsString());
248 // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
249 // to have read access to this directory already.
250 m_localPathsWithAssumedReadAccess.add(baseURL.fileSystemPath());
253 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
255 return checkURLReceivedFromWebProcess(KURL(KURL(), urlString));
258 bool WebProcessProxy::checkURLReceivedFromWebProcess(const KURL& url)
260 // 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.
262 // Any other non-file URL is OK.
263 if (!url.isLocalFile())
266 // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
267 if (m_mayHaveUniversalFileReadSandboxExtension)
270 // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
271 // There are no ".." components, because all URLs received from WebProcess are parsed with KURL, which removes those.
272 String path = url.fileSystemPath();
273 for (HashSet<String>::const_iterator iter = m_localPathsWithAssumedReadAccess.begin(); iter != m_localPathsWithAssumedReadAccess.end(); ++iter) {
274 if (path.startsWith(*iter))
278 // Items in back/forward list have been already checked.
279 // 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.
280 for (WebBackForwardListItemMap::iterator iter = m_backForwardListItemMap.begin(), end = m_backForwardListItemMap.end(); iter != end; ++iter) {
281 if (KURL(KURL(), iter->second->url()).fileSystemPath() == path)
283 if (KURL(KURL(), iter->second->originalURL()).fileSystemPath() == path)
287 // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
288 WTFLogAlways("Received an unexpected URL from the web process: '%s'\n", url.string().utf8().data());
293 bool WebProcessProxy::fullKeyboardAccessEnabled()
299 void WebProcessProxy::addBackForwardItem(uint64_t itemID, const String& originalURL, const String& url, const String& title, const CoreIPC::DataReference& backForwardData)
301 MESSAGE_CHECK_URL(originalURL);
302 MESSAGE_CHECK_URL(url);
304 WebBackForwardListItemMap::AddResult result = m_backForwardListItemMap.add(itemID, 0);
305 if (result.isNewEntry) {
306 result.iterator->second = WebBackForwardListItem::create(originalURL, url, title, backForwardData.data(), backForwardData.size(), itemID);
310 // Update existing item.
311 result.iterator->second->setOriginalURL(originalURL);
312 result.iterator->second->setURL(url);
313 result.iterator->second->setTitle(title);
314 result.iterator->second->setBackForwardData(backForwardData.data(), backForwardData.size());
317 #if ENABLE(PLUGIN_PROCESS)
318 void WebProcessProxy::getPluginProcessConnection(const String& pluginPath, PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
320 PluginProcessManager::shared().getPluginProcessConnection(context()->pluginInfoStore(), pluginPath, reply);
323 void WebProcessProxy::pluginSyncMessageSendTimedOut(const String& pluginPath)
325 PluginProcessManager::shared().pluginSyncMessageSendTimedOut(pluginPath);
329 void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
331 if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
332 didReceiveWebProcessProxyMessage(connection, messageID, arguments);
336 if (messageID.is<CoreIPC::MessageClassWebContext>()
337 || messageID.is<CoreIPC::MessageClassWebContextLegacy>()
338 || messageID.is<CoreIPC::MessageClassDownloadProxy>()
339 || messageID.is<CoreIPC::MessageClassWebApplicationCacheManagerProxy>()
340 #if ENABLE(BATTERY_STATUS)
341 || messageID.is<CoreIPC::MessageClassWebBatteryManagerProxy>()
343 || messageID.is<CoreIPC::MessageClassWebCookieManagerProxy>()
344 || messageID.is<CoreIPC::MessageClassWebDatabaseManagerProxy>()
345 || messageID.is<CoreIPC::MessageClassWebGeolocationManagerProxy>()
346 || messageID.is<CoreIPC::MessageClassWebIconDatabase>()
347 || messageID.is<CoreIPC::MessageClassWebKeyValueStorageManagerProxy>()
348 #if ENABLE(TIZEN_FILE_SYSTEM)
349 || messageID.is<CoreIPC::MessageClassWebLocalFileSystemManagerProxy>()
351 || messageID.is<CoreIPC::MessageClassWebMediaCacheManagerProxy>()
352 #if ENABLE(NETWORK_INFO)
353 || messageID.is<CoreIPC::MessageClassWebNetworkInfoManagerProxy>()
355 || messageID.is<CoreIPC::MessageClassWebNotificationManagerProxy>()
357 || messageID.is<CoreIPC::MessageClassWebSoupRequestManagerProxy>()
359 #if ENABLE(VIBRATION)
360 || messageID.is<CoreIPC::MessageClassWebVibrationProxy>()
362 || messageID.is<CoreIPC::MessageClassWebResourceCacheManagerProxy>()) {
363 m_context->didReceiveMessage(connection, messageID, arguments);
367 uint64_t pageID = arguments->destinationID();
371 WebPageProxy* pageProxy = webPage(pageID);
375 pageProxy->didReceiveMessage(connection, messageID, arguments);
378 void WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, OwnPtr<CoreIPC::ArgumentEncoder>& reply)
380 if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
381 didReceiveSyncWebProcessProxyMessage(connection, messageID, arguments, reply);
385 if (messageID.is<CoreIPC::MessageClassWebContext>() || messageID.is<CoreIPC::MessageClassWebContextLegacy>()
386 #if ENABLE(NETWORK_INFO)
387 || messageID.is<CoreIPC::MessageClassWebNetworkInfoManagerProxy>()
389 || messageID.is<CoreIPC::MessageClassDownloadProxy>() || messageID.is<CoreIPC::MessageClassWebIconDatabase>()) {
390 m_context->didReceiveSyncMessage(connection, messageID, arguments, reply);
394 uint64_t pageID = arguments->destinationID();
398 WebPageProxy* pageProxy = webPage(pageID);
402 pageProxy->didReceiveSyncMessage(connection, messageID, arguments, reply);
405 void WebProcessProxy::didReceiveMessageOnConnectionWorkQueue(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, bool& didHandleMessage)
407 if (messageID.is<CoreIPC::MessageClassWebProcessProxy>())
408 didReceiveWebProcessProxyMessageOnConnectionWorkQueue(connection, messageID, arguments, didHandleMessage);
411 void WebProcessProxy::didClose(CoreIPC::Connection*)
413 // Protect ourselves, as the call to disconnect() below may otherwise cause us
414 // to be deleted before we can finish our work.
415 RefPtr<WebProcessProxy> protect(this);
417 Vector<RefPtr<WebPageProxy> > pages;
418 copyValuesToVector(m_pageMap, pages);
422 for (size_t i = 0, size = pages.size(); i < size; ++i)
423 pages[i]->processDidCrash();
426 void WebProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID)
428 WTFLogAlways("Received an invalid message from the web process with message ID %x\n", messageID.toInt());
430 // Terminate the WebProcesses.
434 void WebProcessProxy::syncMessageSendTimedOut(CoreIPC::Connection*)
438 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*)
440 Vector<RefPtr<WebPageProxy> > pages;
441 copyValuesToVector(m_pageMap, pages);
442 for (size_t i = 0, size = pages.size(); i < size; ++i)
443 pages[i]->processDidBecomeUnresponsive();
446 void WebProcessProxy::interactionOccurredWhileUnresponsive(ResponsivenessTimer*)
448 Vector<RefPtr<WebPageProxy> > pages;
449 copyValuesToVector(m_pageMap, pages);
450 for (size_t i = 0, size = pages.size(); i < size; ++i)
451 pages[i]->interactionOccurredWhileProcessUnresponsive();
454 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*)
456 Vector<RefPtr<WebPageProxy> > pages;
457 copyValuesToVector(m_pageMap, pages);
458 for (size_t i = 0, size = pages.size(); i < size; ++i)
459 pages[i]->processDidBecomeResponsive();
462 void WebProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
464 didFinishLaunching(connectionIdentifier);
467 void WebProcessProxy::didFinishLaunching(ThreadLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
469 didFinishLaunching(connectionIdentifier);
472 void WebProcessProxy::didFinishLaunching(CoreIPC::Connection::Identifier connectionIdentifier)
474 ASSERT(!m_connection);
476 m_connection = WebConnectionToWebProcess::create(this, connectionIdentifier, RunLoop::main());
477 m_connection->connection()->addQueueClient(this);
478 m_connection->connection()->open();
480 for (size_t i = 0; i < m_pendingMessages.size(); ++i) {
481 CoreIPC::Connection::OutgoingMessage& outgoingMessage = m_pendingMessages[i].first;
482 unsigned messageSendFlags = m_pendingMessages[i].second;
483 connection()->sendMessage(outgoingMessage.messageID(), adoptPtr(outgoingMessage.arguments()), messageSendFlags);
486 m_pendingMessages.clear();
488 // Tell the context that we finished launching.
489 m_context->processDidFinishLaunching(this);
492 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
494 return isGoodKey<WebFrameProxyMap>(frameID) ? m_frameMap.get(frameID).get() : 0;
497 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
499 return isGoodKey<WebFrameProxyMap>(frameID) && !m_frameMap.contains(frameID);
502 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
504 ASSERT(canCreateFrame(frameID));
505 m_frameMap.set(frameID, frameProxy);
508 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
510 // If the page is closed before it has had the chance to send the DidCreateMainFrame message
511 // back to the UIProcess, then the frameDestroyed message will still be received because it
512 // gets sent directly to the WebProcessProxy.
513 ASSERT(isGoodKey<WebFrameProxyMap>(frameID));
514 m_frameMap.remove(frameID);
517 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
519 Vector<RefPtr<WebFrameProxy> > frames;
520 copyValuesToVector(m_frameMap, frames);
521 for (size_t i = 0, size = frames.size(); i < size; ++i) {
522 if (frames[i]->page() == page)
523 frames[i]->disconnect();
527 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
530 for (HashMap<uint64_t, RefPtr<WebFrameProxy> >::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
531 if (iter->second->page() == page)
537 void WebProcessProxy::shouldTerminate(bool& shouldTerminate)
539 if (!m_pageMap.isEmpty() || !m_context->shouldTerminate(this)) {
540 shouldTerminate = false;
544 shouldTerminate = true;
546 // We know that the web process is going to terminate so disconnect it from the context.
550 void WebProcessProxy::updateTextCheckerState()
552 if (canSendMessage())
553 send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
556 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
557 void WebProcessProxy::removePlatformSurfaceTextureFromPool(int platformSurfaceId)
559 if (m_pageMap.size() > 0)
560 platformSurfaceTexturePool()->removePlatformSurfaceTexture(this, platformSurfaceId);
564 #if ENABLE(TIZEN_WEBKIT2_MEMORY_SAVING_MODE)
565 void WebProcessProxy::setMemorySavingMode(bool mode)
567 m_memorySavingModeEnabled = mode;
571 // FIXME: appropriate settings will be added.
576 #if ENABLE(TIZEN_WEBKIT2_TILED_AC)
577 void WebProcessProxy::releaseBackingStoreMemory()
579 Vector<RefPtr<WebPageProxy> > pages;
580 copyValuesToVector(m_pageMap, pages);
581 for (size_t i = 0, size = pages.size(); i < size; ++i)
582 pages[i]->purgeBackingStoresOfInactiveView();
585 } // namespace WebKit