diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/WebProcessProxy.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/WebProcessProxy.cpp | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/Source/WebKit2/UIProcess/WebProcessProxy.cpp b/Source/WebKit2/UIProcess/WebProcessProxy.cpp new file mode 100644 index 0000000..c7e9382 --- /dev/null +++ b/Source/WebKit2/UIProcess/WebProcessProxy.cpp @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "WebProcessProxy.h" + +#include "DataReference.h" +#include "PluginInfoStore.h" +#include "PluginProcessManager.h" +#include "TextChecker.h" +#include "TextCheckerState.h" +#include "WebBackForwardListItem.h" +#include "WebContext.h" +#include "WebNavigationDataStore.h" +#include "WebPageProxy.h" +#include "WebProcessManager.h" +#include "WebProcessMessages.h" +#include "WebProcessProxyMessages.h" +#include "WebProcessProxyMessageKinds.h" +#include <WebCore/KURL.h> +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + +using namespace WebCore; + +namespace WebKit { + +template<typename HashMap> +static inline bool isGoodKey(const typename HashMap::KeyType& key) +{ + return key != HashTraits<typename HashMap::KeyType>::emptyValue() && !HashTraits<typename HashMap::KeyType>::isDeletedValue(key); +} + +static uint64_t generatePageID() +{ + static uint64_t uniquePageID = 1; + return uniquePageID++; +} + +PassRefPtr<WebProcessProxy> WebProcessProxy::create(WebContext* context) +{ + return adoptRef(new WebProcessProxy(context)); +} + +WebProcessProxy::WebProcessProxy(WebContext* context) + : m_responsivenessTimer(this) + , m_context(context) +{ + connect(); +} + +WebProcessProxy::~WebProcessProxy() +{ + if (m_connection) + m_connection->invalidate(); + + for (size_t i = 0; i < m_pendingMessages.size(); ++i) + m_pendingMessages[i].releaseArguments(); + + if (m_processLauncher) { + m_processLauncher->invalidate(); + m_processLauncher = 0; + } + + if (m_threadLauncher) { + m_threadLauncher->invalidate(); + m_threadLauncher = 0; + } +} + +void WebProcessProxy::connect() +{ + if (m_context->processModel() == ProcessModelSharedSecondaryThread) { + ASSERT(!m_threadLauncher); + m_threadLauncher = ThreadLauncher::create(this); + } else { + ASSERT(!m_processLauncher); + + ProcessLauncher::LaunchOptions launchOptions; + launchOptions.processType = ProcessLauncher::WebProcess; +#if PLATFORM(MAC) + // We want the web process to match the architecture of the UI process. + launchOptions.architecture = ProcessLauncher::LaunchOptions::MatchCurrentArchitecture; +#endif + m_processLauncher = ProcessLauncher::create(this, launchOptions); + } +} + +bool WebProcessProxy::sendMessage(CoreIPC::MessageID messageID, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments) +{ + // 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 + // a CoreIPC connection. + if (isLaunching()) { + m_pendingMessages.append(CoreIPC::Connection::OutgoingMessage(messageID, arguments)); + return true; + } + + // If the web process has exited, m_connection will be null here. + if (!m_connection) + return false; + + return m_connection->sendMessage(messageID, arguments); +} + +bool WebProcessProxy::isLaunching() const +{ + if (m_processLauncher) + return m_processLauncher->isLaunching(); + if (m_threadLauncher) + return m_threadLauncher->isLaunching(); + + return false; +} + +void WebProcessProxy::terminate() +{ + if (m_processLauncher) + m_processLauncher->terminateProcess(); +} + +WebPageProxy* WebProcessProxy::webPage(uint64_t pageID) const +{ + return m_pageMap.get(pageID).get(); +} + +WebPageProxy* WebProcessProxy::createWebPage(PageClient* pageClient, WebContext* context, WebPageGroup* pageGroup) +{ + ASSERT(context->process() == this); + + unsigned pageID = generatePageID(); + RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageClient, context, pageGroup, pageID); + m_pageMap.set(pageID, webPage); + return webPage.get(); +} + +void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID) +{ + m_pageMap.set(pageID, webPage); +} + +void WebProcessProxy::removeWebPage(uint64_t pageID) +{ + m_pageMap.remove(pageID); +} + +WebProcessProxy::pages_const_iterator WebProcessProxy::pages_begin() +{ + return m_pageMap.begin().values(); +} + +WebProcessProxy::pages_const_iterator WebProcessProxy::pages_end() +{ + return m_pageMap.end().values(); +} + +size_t WebProcessProxy::numberOfPages() +{ + return m_pageMap.size(); +} + +WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const +{ + return m_backForwardListItemMap.get(itemID).get(); +} + +void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item) +{ + // This item was just created by the UIProcess and is being added to the map for the first time + // so we should not already have an item for this ID. + ASSERT(!m_backForwardListItemMap.contains(item->itemID())); + + m_backForwardListItemMap.set(item->itemID(), item); +} + +void WebProcessProxy::addBackForwardItem(uint64_t itemID, const String& originalURL, const String& url, const String& title, const CoreIPC::DataReference& backForwardData) +{ + std::pair<WebBackForwardListItemMap::iterator, bool> result = m_backForwardListItemMap.add(itemID, 0); + if (result.second) { + // New item. + result.first->second = WebBackForwardListItem::create(originalURL, url, title, backForwardData.data(), backForwardData.size(), itemID); + return; + } + + // Update existing item. + result.first->second->setOriginalURL(originalURL); + result.first->second->setURL(url); + result.first->second->setTitle(title); + result.first->second->setBackForwardData(backForwardData.data(), backForwardData.size()); +} + +#if ENABLE(PLUGIN_PROCESS) +void WebProcessProxy::getPluginProcessConnection(const String& pluginPath, CoreIPC::ArgumentEncoder* reply) +{ + PluginProcessManager::shared().getPluginProcessConnection(pluginPath, this, reply); +} +#endif + +void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments) +{ + if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) { + didReceiveWebProcessProxyMessage(connection, messageID, arguments); + return; + } + + if (messageID.is<CoreIPC::MessageClassWebContext>() + || messageID.is<CoreIPC::MessageClassWebContextLegacy>() + || messageID.is<CoreIPC::MessageClassDownloadProxy>() + || messageID.is<CoreIPC::MessageClassWebDatabaseManagerProxy>() + || messageID.is<CoreIPC::MessageClassWebGeolocationManagerProxy>()) { + m_context->didReceiveMessage(connection, messageID, arguments); + return; + } + + uint64_t pageID = arguments->destinationID(); + if (!pageID) + return; + + WebPageProxy* pageProxy = webPage(pageID); + if (!pageProxy) + return; + + pageProxy->didReceiveMessage(connection, messageID, arguments); +} + +CoreIPC::SyncReplyMode WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply) +{ +#if ENABLE(PLUGIN_PROCESS) + if (messageID.is<CoreIPC::MessageClassWebProcessProxyLegacy>()) { + switch (messageID.get<WebProcessProxyLegacyMessage::Kind>()) { + case WebProcessProxyLegacyMessage::GetPluginProcessConnection: { + String pluginPath; + + if (!arguments->decode(CoreIPC::Out(pluginPath))) + return CoreIPC::AutomaticReply; + + getPluginProcessConnection(pluginPath, reply); + return CoreIPC::ManualReply; + } + } + } +#endif + + if (messageID.is<CoreIPC::MessageClassWebContext>() || messageID.is<CoreIPC::MessageClassWebContextLegacy>() || messageID.is<CoreIPC::MessageClassDownloadProxy>()) + return m_context->didReceiveSyncMessage(connection, messageID, arguments, reply); + + uint64_t pageID = arguments->destinationID(); + if (!pageID) + return CoreIPC::AutomaticReply; + + WebPageProxy* pageProxy = webPage(pageID); + if (!pageProxy) + return CoreIPC::AutomaticReply; + + pageProxy->didReceiveSyncMessage(connection, messageID, arguments, reply); + return CoreIPC::AutomaticReply; +} + +void WebProcessProxy::didClose(CoreIPC::Connection*) +{ + // Protect ourselves, as the call to the shared WebProcessManager's processDidClose() + // below may otherwise cause us to be deleted before we can finish our work. + RefPtr<WebProcessProxy> protect(this); + + m_connection = nullptr; + m_responsivenessTimer.stop(); + + Vector<RefPtr<WebFrameProxy> > frames; + copyValuesToVector(m_frameMap, frames); + + for (size_t i = 0, size = frames.size(); i < size; ++i) + frames[i]->disconnect(); + m_frameMap.clear(); + + Vector<RefPtr<WebPageProxy> > pages; + copyValuesToVector(m_pageMap, pages); + + m_context->processDidClose(this); + + WebProcessManager::shared().processDidClose(this, m_context); + + for (size_t i = 0, size = pages.size(); i < size; ++i) + pages[i]->processDidCrash(); +} + +void WebProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID) +{ + // We received an invalid message from the web process, invalidate our connection and kill it. + m_connection->invalidate(); + + terminate(); +} + +void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*) +{ + Vector<RefPtr<WebPageProxy> > pages; + copyValuesToVector(m_pageMap, pages); + for (size_t i = 0, size = pages.size(); i < size; ++i) + pages[i]->processDidBecomeUnresponsive(); +} + +void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*) +{ + Vector<RefPtr<WebPageProxy> > pages; + copyValuesToVector(m_pageMap, pages); + for (size_t i = 0, size = pages.size(); i < size; ++i) + pages[i]->processDidBecomeResponsive(); +} + +void WebProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier) +{ + didFinishLaunching(connectionIdentifier); +} + +void WebProcessProxy::didFinishLaunching(ThreadLauncher*, CoreIPC::Connection::Identifier connectionIdentifier) +{ + didFinishLaunching(connectionIdentifier); +} + +void WebProcessProxy::didFinishLaunching(CoreIPC::Connection::Identifier connectionIdentifier) +{ + ASSERT(!m_connection); + + m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main()); +#if PLATFORM(MAC) + m_connection->setShouldCloseConnectionOnMachExceptions(); +#endif + + m_connection->open(); + + for (size_t i = 0; i < m_pendingMessages.size(); ++i) { + CoreIPC::Connection::OutgoingMessage& outgoingMessage = m_pendingMessages[i]; + m_connection->sendMessage(outgoingMessage.messageID(), adoptPtr(outgoingMessage.arguments())); + } + + m_pendingMessages.clear(); + + // Tell the context that we finished launching. + m_context->processDidFinishLaunching(this); +} + +WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const +{ + return isGoodKey<WebFrameProxyMap>(frameID) ? m_frameMap.get(frameID).get() : 0; +} + +bool WebProcessProxy::canCreateFrame(uint64_t frameID) const +{ + return isGoodKey<WebFrameProxyMap>(frameID) && !m_frameMap.contains(frameID); +} + +void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy) +{ + ASSERT(canCreateFrame(frameID)); + m_frameMap.set(frameID, frameProxy); +} + +void WebProcessProxy::didDestroyFrame(uint64_t frameID) +{ + // If the page is closed before it has had the chance to send the DidCreateMainFrame message + // back to the UIProcess, then the frameDestroyed message will still be received because it + // gets sent directly to the WebProcessProxy. + ASSERT(isGoodKey<WebFrameProxyMap>(frameID)); + m_frameMap.remove(frameID); +} + +void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page) +{ + Vector<RefPtr<WebFrameProxy> > frames; + copyValuesToVector(m_frameMap, frames); + for (size_t i = 0, size = frames.size(); i < size; ++i) { + if (frames[i]->page() == page) + frames[i]->disconnect(); + } +} + +size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const +{ + size_t result = 0; + for (HashMap<uint64_t, RefPtr<WebFrameProxy> >::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) { + if (iter->second->page() == page) + ++result; + } + return result; +} + +void WebProcessProxy::updateTextCheckerState() +{ + if (!isValid()) + return; + + send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0); +} + +} // namespace WebKit |