WebKit2/UIProcess/WebProcessProxy.cpp
changeset 0 4f2f89ce4247
--- /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 <WebCore/KURL.h>
+#include <WebCore/PlatformString.h>
+#include <wtf/text/CString.h>
+
+#if ENABLE(WEB_PROCESS_SANDBOX)
+#include <sandbox.h>
+#endif
+
+using namespace WebCore;
+
+namespace WebKit {
+
+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();
+
+    // 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<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;
+    }
+    
+    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<WebPageProxy> 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<PluginInfo>& 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<WebBackForwardListItemMap::iterator, bool> 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<CoreIPC::MessageClassWebProcessProxy>()) {
+        switch (messageID.get<WebProcessProxyMessage::Kind>()) {
+            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<CoreIPC::MessageClassWebProcessProxy>()) {
+        switch (messageID.get<WebProcessProxyMessage::Kind>()) {
+            case WebProcessProxyMessage::GetPlugins: {
+                bool refresh;
+                if (!arguments->decode(refresh))
+                    return;
+                
+                // FIXME: We should not do this on the main thread!
+                Vector<PluginInfo> 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<RefPtr<WebPageProxy> > 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<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*, 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