diff -r 000000000000 -r 4f2f89ce4247 WebKit2/UIProcess/WebProcessProxy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebKit2/UIProcess/WebProcessProxy.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2010 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 "PluginInfoStore.h" +#include "ProcessLauncher.h" +#include "WebBackForwardListItem.h" +#include "WebContext.h" +#include "WebPageNamespace.h" +#include "WebPageProxy.h" +#include "WebProcessManager.h" +#include "WebProcessMessageKinds.h" +#include "WebProcessProxyMessageKinds.h" +#include +#include +#include + +#if ENABLE(WEB_PROCESS_SANDBOX) +#include +#endif + +using namespace WebCore; + +namespace WebKit { + +static uint64_t generatePageID() +{ + static uint64_t uniquePageID = 1; + return uniquePageID++; +} + +PassRefPtr WebProcessProxy::create(WebContext* context) +{ + return adoptRef(new WebProcessProxy(context)); +} + +WebProcessProxy::WebProcessProxy(WebContext* context) + : m_responsivenessTimer(this) + , m_context(context) +{ + connect(); + + // FIXME: Instead of sending three separate initialization related messages here, we should just send a + // single "Initialize" messages with a struct that has all the needed information. + send(WebProcessMessage::SetApplicationCacheDirectory, 0, CoreIPC::In(m_context->applicationCacheDirectory())); + + // FIXME: We could instead send the bundle path as part of the arguments to process creation? + // Would that be better than sending a connection? + if (!context->injectedBundlePath().isEmpty()) { +#if ENABLE(WEB_PROCESS_SANDBOX) + char *sandboxBundleToken = NULL; + CString injectedBundlePath = context->injectedBundlePath().utf8(); + sandbox_issue_extension(injectedBundlePath.data(), &sandboxBundleToken); + send(WebProcessMessage::LoadInjectedBundle, 0, CoreIPC::In(context->injectedBundlePath(), String::fromUTF8(sandboxBundleToken))); + if (sandboxBundleToken) + free(sandboxBundleToken); +#else + send(WebProcessMessage::LoadInjectedBundle, 0, CoreIPC::In(context->injectedBundlePath())); +#endif + } + +#if USE(ACCELERATED_COMPOSITING) + setUpAcceleratedCompositing(); +#endif + +} + +WebProcessProxy::~WebProcessProxy() +{ + ASSERT(!m_connection); + + for (size_t i = 0; i < m_pendingMessages.size(); ++i) + m_pendingMessages[i].destroy(); + + if (m_processLauncher) { + m_processLauncher->invalidate(); + m_processLauncher = 0; + } +} + +void WebProcessProxy::connect() +{ + if (m_context->processModel() == ProcessModelSharedSecondaryThread) { + CoreIPC::Connection::Identifier connectionIdentifier = ProcessLauncher::createWebThread(); + didFinishLaunching(0, connectionIdentifier); + return; + } + + ASSERT(!m_processLauncher); + m_processLauncher = ProcessLauncher::create(this); +} + +bool WebProcessProxy::sendMessage(CoreIPC::MessageID messageID, PassOwnPtr 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; + } + + return m_connection->sendMessage(messageID, arguments); +} + +void WebProcessProxy::terminate() +{ + if (m_processLauncher) + m_processLauncher->terminateProcess(); +} + +#if USE(ACCELERATED_COMPOSITING) && !PLATFORM(MAC) +void WebProcessProxy::setUpAcceleratedCompositing() +{ +} +#endif + +WebPageProxy* WebProcessProxy::webPage(uint64_t pageID) const +{ + return m_pageMap.get(pageID).get(); +} + +WebPageProxy* WebProcessProxy::createWebPage(WebPageNamespace* pageNamespace) +{ + ASSERT(pageNamespace->process() == this); + + unsigned pageID = generatePageID(); + RefPtr webPage = WebPageProxy::create(pageNamespace, 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::forwardMessageToWebContext(const String& message) +{ + m_context->didRecieveMessageFromInjectedBundle(message); +} + +void WebProcessProxy::getPlugins(bool refresh, Vector& plugins) +{ + if (refresh) + m_context->pluginInfoStore()->refresh(); + m_context->pluginInfoStore()->getPlugins(plugins); +} + +void WebProcessProxy::getPluginHostConnection(const String& mimeType, const KURL& url, WebCore::String& pluginPath) +{ + String newMimeType = mimeType.lower(); + + PluginInfoStore::Plugin plugin = m_context->pluginInfoStore()->findPlugin(newMimeType, url); + if (!plugin.path) + return; + + pluginPath = plugin.path; +} + +void WebProcessProxy::addOrUpdateBackForwardListItem(uint64_t itemID, const String& originalURL, const String& url, const String& title) +{ + std::pair result = m_backForwardListItemMap.add(itemID, 0); + if (result.second) { + // New item. + result.first->second = WebBackForwardListItem::create(originalURL, url, title, itemID); + return; + } + + // Update existing item. + result.first->second->setOriginalURL(originalURL); + result.first->second->setURL(url); + result.first->second->setTitle(title); +} + +void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments) +{ + if (messageID.is()) { + switch (messageID.get()) { + case WebProcessProxyMessage::PostMessage: { + String message; + if (!arguments->decode(CoreIPC::Out(message))) + return; + + forwardMessageToWebContext(message); + return; + } + case WebProcessProxyMessage::AddBackForwardItem: { + uint64_t itemID; + String originalURL; + String url; + String title; + if (!arguments->decode(CoreIPC::Out(itemID, originalURL, url, title))) + return; + addOrUpdateBackForwardListItem(itemID, originalURL, url, title); + return; + } + + // These are synchronous messages and should never be handled here. + case WebProcessProxyMessage::GetPlugins: + case WebProcessProxyMessage::GetPluginHostConnection: + ASSERT_NOT_REACHED(); + break; + } + } + + uint64_t pageID = arguments->destinationID(); + if (!pageID) + return; + + WebPageProxy* pageProxy = webPage(pageID); + if (!pageProxy) + return; + + pageProxy->didReceiveMessage(connection, messageID, *arguments); +} + +void WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply) +{ + if (messageID.is()) { + switch (messageID.get()) { + case WebProcessProxyMessage::GetPlugins: { + bool refresh; + if (!arguments->decode(refresh)) + return; + + // FIXME: We should not do this on the main thread! + Vector plugins; + getPlugins(refresh, plugins); + + reply->encode(plugins); + break; + } + + case WebProcessProxyMessage::GetPluginHostConnection: { +#if PLATFORM(MAC) + String mimeType; + String urlString; + + if (!arguments->decode(CoreIPC::Out(mimeType, urlString))) + return; + + String pluginPath; + getPluginHostConnection(mimeType, KURL(ParsedURLString, urlString), pluginPath); + reply->encode(CoreIPC::In(pluginPath)); +#endif + break; + } + + // These are asynchronous messages and should never be handled here. + case WebProcessProxyMessage::PostMessage: + case WebProcessProxyMessage::AddBackForwardItem: + ASSERT_NOT_REACHED(); + break; + } + } + + uint64_t pageID = arguments->destinationID(); + if (!pageID) + return; + + WebPageProxy* pageProxy = webPage(pageID); + if (!pageProxy) + return; + + pageProxy->didReceiveSyncMessage(connection, messageID, *arguments, *reply); +} + +void WebProcessProxy::didClose(CoreIPC::Connection*) +{ + m_connection = 0; + m_responsivenessTimer.stop(); + + Vector > pages; + copyValuesToVector(m_pageMap, pages); + + for (size_t i = 0, size = pages.size(); i < size; ++i) + pages[i]->processDidExit(); + + // This may cause us to be deleted. + WebProcessManager::shared().processDidClose(this, m_context); +} + +void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*) +{ + Vector > pages; + copyValuesToVector(m_pageMap, pages); + for (size_t i = 0, size = pages.size(); i < size; ++i) + pages[i]->processDidBecomeUnresponsive(); +} + +void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*) +{ + Vector > pages; + copyValuesToVector(m_pageMap, pages); + for (size_t i = 0, size = pages.size(); i < size; ++i) + pages[i]->processDidBecomeResponsive(); +} + +void WebProcessProxy::didFinishLaunching(ProcessLauncher*, const CoreIPC::Connection::Identifier& connectionIdentifier) +{ + ASSERT(!m_connection); + + m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main()); + 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(); +} + +} // namespace WebKit