WebKit2/UIProcess/WebProcessProxy.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2010 Apple Inc. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     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.
       
    12  *
       
    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.
       
    24  */
       
    25 
       
    26 #include "WebProcessProxy.h"
       
    27 
       
    28 #include "PluginInfoStore.h"
       
    29 #include "ProcessLauncher.h"
       
    30 #include "WebBackForwardListItem.h"
       
    31 #include "WebContext.h"
       
    32 #include "WebPageNamespace.h"
       
    33 #include "WebPageProxy.h"
       
    34 #include "WebProcessManager.h"
       
    35 #include "WebProcessMessageKinds.h"
       
    36 #include "WebProcessProxyMessageKinds.h"
       
    37 #include <WebCore/KURL.h>
       
    38 #include <WebCore/PlatformString.h>
       
    39 #include <wtf/text/CString.h>
       
    40 
       
    41 #if ENABLE(WEB_PROCESS_SANDBOX)
       
    42 #include <sandbox.h>
       
    43 #endif
       
    44 
       
    45 using namespace WebCore;
       
    46 
       
    47 namespace WebKit {
       
    48 
       
    49 static uint64_t generatePageID()
       
    50 {
       
    51     static uint64_t uniquePageID = 1;
       
    52     return uniquePageID++;
       
    53 }
       
    54 
       
    55 PassRefPtr<WebProcessProxy> WebProcessProxy::create(WebContext* context)
       
    56 {
       
    57     return adoptRef(new WebProcessProxy(context));
       
    58 }
       
    59 
       
    60 WebProcessProxy::WebProcessProxy(WebContext* context)
       
    61     : m_responsivenessTimer(this)
       
    62     , m_context(context)
       
    63 {
       
    64     connect();
       
    65 
       
    66     // FIXME: Instead of sending three separate initialization related messages here, we should just send a
       
    67     // single "Initialize" messages with a struct that has all the needed information.
       
    68     send(WebProcessMessage::SetApplicationCacheDirectory, 0, CoreIPC::In(m_context->applicationCacheDirectory()));
       
    69 
       
    70     // FIXME: We could instead send the bundle path as part of the arguments to process creation?
       
    71     // Would that be better than sending a connection?
       
    72     if (!context->injectedBundlePath().isEmpty()) {
       
    73 #if ENABLE(WEB_PROCESS_SANDBOX)
       
    74         char *sandboxBundleToken = NULL;
       
    75         CString injectedBundlePath = context->injectedBundlePath().utf8();
       
    76         sandbox_issue_extension(injectedBundlePath.data(), &sandboxBundleToken);
       
    77         send(WebProcessMessage::LoadInjectedBundle, 0, CoreIPC::In(context->injectedBundlePath(), String::fromUTF8(sandboxBundleToken)));
       
    78         if (sandboxBundleToken)
       
    79             free(sandboxBundleToken);
       
    80 #else
       
    81         send(WebProcessMessage::LoadInjectedBundle, 0, CoreIPC::In(context->injectedBundlePath()));
       
    82 #endif
       
    83     }
       
    84 
       
    85 #if USE(ACCELERATED_COMPOSITING)
       
    86     setUpAcceleratedCompositing();
       
    87 #endif
       
    88 
       
    89 }
       
    90 
       
    91 WebProcessProxy::~WebProcessProxy()
       
    92 {
       
    93     ASSERT(!m_connection);
       
    94     
       
    95     for (size_t i = 0; i < m_pendingMessages.size(); ++i)
       
    96         m_pendingMessages[i].destroy();
       
    97 
       
    98     if (m_processLauncher) {
       
    99         m_processLauncher->invalidate();
       
   100         m_processLauncher = 0;
       
   101     }
       
   102 }
       
   103 
       
   104 void WebProcessProxy::connect()
       
   105 {
       
   106     if (m_context->processModel() == ProcessModelSharedSecondaryThread) {
       
   107         CoreIPC::Connection::Identifier connectionIdentifier = ProcessLauncher::createWebThread();
       
   108         didFinishLaunching(0, connectionIdentifier);
       
   109         return;
       
   110     }
       
   111 
       
   112     ASSERT(!m_processLauncher);
       
   113     m_processLauncher = ProcessLauncher::create(this);
       
   114 }
       
   115 
       
   116 bool WebProcessProxy::sendMessage(CoreIPC::MessageID messageID, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments)
       
   117 {
       
   118     // 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
       
   119     // a CoreIPC connection.
       
   120     if (isLaunching()) {
       
   121         m_pendingMessages.append(CoreIPC::Connection::OutgoingMessage(messageID, arguments));
       
   122         return true;
       
   123     }
       
   124     
       
   125     return m_connection->sendMessage(messageID, arguments);
       
   126 }
       
   127 
       
   128 void WebProcessProxy::terminate()
       
   129 {
       
   130     if (m_processLauncher)
       
   131         m_processLauncher->terminateProcess();
       
   132 }
       
   133 
       
   134 #if USE(ACCELERATED_COMPOSITING) && !PLATFORM(MAC)
       
   135 void WebProcessProxy::setUpAcceleratedCompositing()
       
   136 {
       
   137 }
       
   138 #endif
       
   139 
       
   140 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID) const
       
   141 {
       
   142     return m_pageMap.get(pageID).get();
       
   143 }
       
   144 
       
   145 WebPageProxy* WebProcessProxy::createWebPage(WebPageNamespace* pageNamespace)
       
   146 {
       
   147     ASSERT(pageNamespace->process() == this);
       
   148 
       
   149     unsigned pageID = generatePageID();
       
   150     RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageNamespace, pageID);
       
   151     m_pageMap.set(pageID, webPage);
       
   152     return webPage.get();
       
   153 }
       
   154 
       
   155 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
       
   156 {
       
   157     m_pageMap.set(pageID, webPage);
       
   158 }
       
   159 
       
   160 void WebProcessProxy::removeWebPage(uint64_t pageID)
       
   161 {
       
   162     m_pageMap.remove(pageID);
       
   163 }
       
   164 
       
   165 WebProcessProxy::pages_const_iterator WebProcessProxy::pages_begin()
       
   166 {
       
   167     return m_pageMap.begin().values();
       
   168 }
       
   169 
       
   170 WebProcessProxy::pages_const_iterator WebProcessProxy::pages_end()
       
   171 {
       
   172     return m_pageMap.end().values();
       
   173 }
       
   174 
       
   175 size_t WebProcessProxy::numberOfPages()
       
   176 {
       
   177     return m_pageMap.size();
       
   178 }
       
   179 
       
   180 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
       
   181 {
       
   182     return m_backForwardListItemMap.get(itemID).get();
       
   183 }
       
   184 
       
   185 void WebProcessProxy::forwardMessageToWebContext(const String& message)
       
   186 {
       
   187     m_context->didRecieveMessageFromInjectedBundle(message);
       
   188 }
       
   189 
       
   190 void WebProcessProxy::getPlugins(bool refresh, Vector<PluginInfo>& plugins)
       
   191 {
       
   192     if (refresh)
       
   193         m_context->pluginInfoStore()->refresh();
       
   194     m_context->pluginInfoStore()->getPlugins(plugins);
       
   195 }
       
   196 
       
   197 void WebProcessProxy::getPluginHostConnection(const String& mimeType, const KURL& url, WebCore::String& pluginPath)
       
   198 {
       
   199     String newMimeType = mimeType.lower();
       
   200 
       
   201     PluginInfoStore::Plugin plugin = m_context->pluginInfoStore()->findPlugin(newMimeType, url);
       
   202     if (!plugin.path)
       
   203         return;
       
   204 
       
   205     pluginPath = plugin.path;
       
   206 }
       
   207 
       
   208 void WebProcessProxy::addOrUpdateBackForwardListItem(uint64_t itemID, const String& originalURL, const String& url, const String& title)
       
   209 {
       
   210     std::pair<WebBackForwardListItemMap::iterator, bool> result = m_backForwardListItemMap.add(itemID, 0);
       
   211     if (result.second) {
       
   212         // New item.
       
   213         result.first->second = WebBackForwardListItem::create(originalURL, url, title, itemID);
       
   214         return;
       
   215     }
       
   216 
       
   217     // Update existing item.
       
   218     result.first->second->setOriginalURL(originalURL);
       
   219     result.first->second->setURL(url);
       
   220     result.first->second->setTitle(title);
       
   221 }
       
   222 
       
   223 void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
       
   224 {
       
   225     if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
       
   226         switch (messageID.get<WebProcessProxyMessage::Kind>()) {
       
   227             case WebProcessProxyMessage::PostMessage: {
       
   228                 String message;
       
   229                 if (!arguments->decode(CoreIPC::Out(message)))
       
   230                     return;
       
   231 
       
   232                 forwardMessageToWebContext(message);
       
   233                 return;
       
   234             }
       
   235             case WebProcessProxyMessage::AddBackForwardItem: {
       
   236                 uint64_t itemID;
       
   237                 String originalURL;
       
   238                 String url;
       
   239                 String title;
       
   240                 if (!arguments->decode(CoreIPC::Out(itemID, originalURL, url, title)))
       
   241                     return;
       
   242                 addOrUpdateBackForwardListItem(itemID, originalURL, url, title);
       
   243                 return;
       
   244             }
       
   245 
       
   246             // These are synchronous messages and should never be handled here.
       
   247             case WebProcessProxyMessage::GetPlugins:
       
   248             case WebProcessProxyMessage::GetPluginHostConnection:
       
   249                 ASSERT_NOT_REACHED();
       
   250                 break;
       
   251         }
       
   252     }
       
   253 
       
   254     uint64_t pageID = arguments->destinationID();
       
   255     if (!pageID)
       
   256         return;
       
   257 
       
   258     WebPageProxy* pageProxy = webPage(pageID);
       
   259     if (!pageProxy)
       
   260         return;
       
   261     
       
   262     pageProxy->didReceiveMessage(connection, messageID, *arguments);    
       
   263 }
       
   264 
       
   265 void WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply)
       
   266 {
       
   267     if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
       
   268         switch (messageID.get<WebProcessProxyMessage::Kind>()) {
       
   269             case WebProcessProxyMessage::GetPlugins: {
       
   270                 bool refresh;
       
   271                 if (!arguments->decode(refresh))
       
   272                     return;
       
   273                 
       
   274                 // FIXME: We should not do this on the main thread!
       
   275                 Vector<PluginInfo> plugins;
       
   276                 getPlugins(refresh, plugins);
       
   277 
       
   278                 reply->encode(plugins);
       
   279                 break;
       
   280             }
       
   281 
       
   282             case WebProcessProxyMessage::GetPluginHostConnection: {
       
   283 #if PLATFORM(MAC)
       
   284                 String mimeType;
       
   285                 String urlString;
       
   286                 
       
   287                 if (!arguments->decode(CoreIPC::Out(mimeType, urlString)))
       
   288                     return;
       
   289                 
       
   290                 String pluginPath;
       
   291                 getPluginHostConnection(mimeType, KURL(ParsedURLString, urlString), pluginPath);
       
   292                 reply->encode(CoreIPC::In(pluginPath));
       
   293 #endif
       
   294                 break;
       
   295             }
       
   296 
       
   297             // These are asynchronous messages and should never be handled here.
       
   298             case WebProcessProxyMessage::PostMessage:
       
   299             case WebProcessProxyMessage::AddBackForwardItem:
       
   300                 ASSERT_NOT_REACHED();
       
   301                 break;
       
   302         }
       
   303     }
       
   304     
       
   305     uint64_t pageID = arguments->destinationID();
       
   306     if (!pageID)
       
   307         return;
       
   308     
       
   309     WebPageProxy* pageProxy = webPage(pageID);
       
   310     if (!pageProxy)
       
   311         return;
       
   312     
       
   313     pageProxy->didReceiveSyncMessage(connection, messageID, *arguments, *reply);
       
   314 }
       
   315 
       
   316 void WebProcessProxy::didClose(CoreIPC::Connection*)
       
   317 {
       
   318     m_connection = 0;
       
   319     m_responsivenessTimer.stop();
       
   320 
       
   321     Vector<RefPtr<WebPageProxy> > pages;
       
   322     copyValuesToVector(m_pageMap, pages);
       
   323 
       
   324     for (size_t i = 0, size = pages.size(); i < size; ++i)
       
   325         pages[i]->processDidExit();
       
   326 
       
   327     // This may cause us to be deleted.
       
   328     WebProcessManager::shared().processDidClose(this, m_context);
       
   329 }
       
   330 
       
   331 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*)
       
   332 {
       
   333     Vector<RefPtr<WebPageProxy> > pages;
       
   334     copyValuesToVector(m_pageMap, pages);
       
   335     for (size_t i = 0, size = pages.size(); i < size; ++i)
       
   336         pages[i]->processDidBecomeUnresponsive();
       
   337 }
       
   338 
       
   339 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*)
       
   340 {
       
   341     Vector<RefPtr<WebPageProxy> > pages;
       
   342     copyValuesToVector(m_pageMap, pages);
       
   343     for (size_t i = 0, size = pages.size(); i < size; ++i)
       
   344         pages[i]->processDidBecomeResponsive();
       
   345 }
       
   346 
       
   347 void WebProcessProxy::didFinishLaunching(ProcessLauncher*, const CoreIPC::Connection::Identifier& connectionIdentifier)
       
   348 {
       
   349     ASSERT(!m_connection);
       
   350     
       
   351     m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main());
       
   352     m_connection->open();
       
   353     
       
   354     for (size_t i = 0; i < m_pendingMessages.size(); ++i) {
       
   355         CoreIPC::Connection::OutgoingMessage& outgoingMessage = m_pendingMessages[i];
       
   356         m_connection->sendMessage(outgoingMessage.messageID(), adoptPtr(outgoingMessage.arguments()));
       
   357     }
       
   358 
       
   359     m_pendingMessages.clear();    
       
   360 }
       
   361 
       
   362 } // namespace WebKit