Home | History | Annotate | Download | only in UIProcess
      1 /*
      2  * Copyright (C) 2010, 2011 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 "config.h"
     27 #include "WebProcessProxy.h"
     28 
     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 "WebPageProxy.h"
     38 #include "WebProcessMessages.h"
     39 #include "WebProcessProxyMessages.h"
     40 #include <WebCore/KURL.h>
     41 #include <wtf/text/CString.h>
     42 #include <wtf/text/WTFString.h>
     43 
     44 using namespace WebCore;
     45 using namespace std;
     46 
     47 namespace WebKit {
     48 
     49 template<typename HashMap>
     50 static inline bool isGoodKey(const typename HashMap::KeyType& key)
     51 {
     52     return key != HashTraits<typename HashMap::KeyType>::emptyValue() && !HashTraits<typename HashMap::KeyType>::isDeletedValue(key);
     53 }
     54 
     55 static uint64_t generatePageID()
     56 {
     57     static uint64_t uniquePageID = 1;
     58     return uniquePageID++;
     59 }
     60 
     61 PassRefPtr<WebProcessProxy> WebProcessProxy::create(PassRefPtr<WebContext> context)
     62 {
     63     return adoptRef(new WebProcessProxy(context));
     64 }
     65 
     66 WebProcessProxy::WebProcessProxy(PassRefPtr<WebContext> context)
     67     : m_responsivenessTimer(this)
     68     , m_context(context)
     69 {
     70     connect();
     71 }
     72 
     73 WebProcessProxy::~WebProcessProxy()
     74 {
     75     if (m_connection)
     76         m_connection->invalidate();
     77 
     78     for (size_t i = 0; i < m_pendingMessages.size(); ++i)
     79         m_pendingMessages[i].first.releaseArguments();
     80 
     81     if (m_processLauncher) {
     82         m_processLauncher->invalidate();
     83         m_processLauncher = 0;
     84     }
     85 
     86     if (m_threadLauncher) {
     87         m_threadLauncher->invalidate();
     88         m_threadLauncher = 0;
     89     }
     90 }
     91 
     92 void WebProcessProxy::connect()
     93 {
     94     if (m_context->processModel() == ProcessModelSharedSecondaryThread) {
     95         ASSERT(!m_threadLauncher);
     96         m_threadLauncher = ThreadLauncher::create(this);
     97     } else {
     98         ASSERT(!m_processLauncher);
     99 
    100         ProcessLauncher::LaunchOptions launchOptions;
    101         launchOptions.processType = ProcessLauncher::WebProcess;
    102 
    103 #if PLATFORM(MAC)
    104         // We want the web process to match the architecture of the UI process.
    105         launchOptions.architecture = ProcessLauncher::LaunchOptions::MatchCurrentArchitecture;
    106         launchOptions.executableHeap = false;
    107 #endif
    108         m_processLauncher = ProcessLauncher::create(this, launchOptions);
    109     }
    110 }
    111 
    112 void WebProcessProxy::disconnect()
    113 {
    114     if (m_connection) {
    115         m_connection->invalidate();
    116         m_connection = nullptr;
    117     }
    118 
    119     m_responsivenessTimer.stop();
    120 
    121     Vector<RefPtr<WebFrameProxy> > frames;
    122     copyValuesToVector(m_frameMap, frames);
    123 
    124     for (size_t i = 0, size = frames.size(); i < size; ++i)
    125         frames[i]->disconnect();
    126     m_frameMap.clear();
    127 
    128     m_context->disconnectProcess(this);
    129 }
    130 
    131 bool WebProcessProxy::sendMessage(CoreIPC::MessageID messageID, PassOwnPtr<CoreIPC::ArgumentEncoder> arguments, unsigned messageSendFlags)
    132 {
    133     // 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
    134     // a CoreIPC connection.
    135     if (isLaunching()) {
    136         m_pendingMessages.append(make_pair(CoreIPC::Connection::OutgoingMessage(messageID, arguments), messageSendFlags));
    137         return true;
    138     }
    139 
    140     // If the web process has exited, m_connection will be null here.
    141     if (!m_connection)
    142         return false;
    143 
    144     return m_connection->sendMessage(messageID, arguments, messageSendFlags);
    145 }
    146 
    147 bool WebProcessProxy::isLaunching() const
    148 {
    149     if (m_processLauncher)
    150         return m_processLauncher->isLaunching();
    151     if (m_threadLauncher)
    152         return m_threadLauncher->isLaunching();
    153 
    154     return false;
    155 }
    156 
    157 void WebProcessProxy::terminate()
    158 {
    159     if (m_processLauncher)
    160         m_processLauncher->terminateProcess();
    161 }
    162 
    163 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID) const
    164 {
    165     return m_pageMap.get(pageID);
    166 }
    167 
    168 PassRefPtr<WebPageProxy> WebProcessProxy::createWebPage(PageClient* pageClient, WebContext* context, WebPageGroup* pageGroup)
    169 {
    170     ASSERT(context->process() == this);
    171 
    172     unsigned pageID = generatePageID();
    173     RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageClient, this, pageGroup, pageID);
    174     m_pageMap.set(pageID, webPage.get());
    175     return webPage.release();
    176 }
    177 
    178 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
    179 {
    180     m_pageMap.set(pageID, webPage);
    181 }
    182 
    183 void WebProcessProxy::removeWebPage(uint64_t pageID)
    184 {
    185     m_pageMap.remove(pageID);
    186 }
    187 
    188 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
    189 {
    190     return m_backForwardListItemMap.get(itemID).get();
    191 }
    192 
    193 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item)
    194 {
    195     // This item was just created by the UIProcess and is being added to the map for the first time
    196     // so we should not already have an item for this ID.
    197     ASSERT(!m_backForwardListItemMap.contains(item->itemID()));
    198 
    199     m_backForwardListItemMap.set(item->itemID(), item);
    200 }
    201 
    202 void WebProcessProxy::addBackForwardItem(uint64_t itemID, const String& originalURL, const String& url, const String& title, const CoreIPC::DataReference& backForwardData)
    203 {
    204     std::pair<WebBackForwardListItemMap::iterator, bool> result = m_backForwardListItemMap.add(itemID, 0);
    205     if (result.second) {
    206         // New item.
    207         result.first->second = WebBackForwardListItem::create(originalURL, url, title, backForwardData.data(), backForwardData.size(), itemID);
    208         return;
    209     }
    210 
    211     // Update existing item.
    212     result.first->second->setOriginalURL(originalURL);
    213     result.first->second->setURL(url);
    214     result.first->second->setTitle(title);
    215     result.first->second->setBackForwardData(backForwardData.data(), backForwardData.size());
    216 }
    217 
    218 #if ENABLE(PLUGIN_PROCESS)
    219 void WebProcessProxy::getPluginProcessConnection(const String& pluginPath, PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
    220 {
    221     PluginProcessManager::shared().getPluginProcessConnection(context()->pluginInfoStore(), pluginPath, reply);
    222 }
    223 
    224 void WebProcessProxy::pluginSyncMessageSendTimedOut(const String& pluginPath)
    225 {
    226     PluginProcessManager::shared().pluginSyncMessageSendTimedOut(pluginPath);
    227 }
    228 #endif
    229 
    230 void WebProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
    231 {
    232     if (messageID.is<CoreIPC::MessageClassWebProcessProxy>()) {
    233         didReceiveWebProcessProxyMessage(connection, messageID, arguments);
    234         return;
    235     }
    236 
    237     if (messageID.is<CoreIPC::MessageClassWebContext>()
    238         || messageID.is<CoreIPC::MessageClassWebContextLegacy>()
    239         || messageID.is<CoreIPC::MessageClassDownloadProxy>()
    240         || messageID.is<CoreIPC::MessageClassWebApplicationCacheManagerProxy>()
    241         || messageID.is<CoreIPC::MessageClassWebCookieManagerProxy>()
    242         || messageID.is<CoreIPC::MessageClassWebDatabaseManagerProxy>()
    243         || messageID.is<CoreIPC::MessageClassWebGeolocationManagerProxy>()
    244         || messageID.is<CoreIPC::MessageClassWebIconDatabase>()
    245         || messageID.is<CoreIPC::MessageClassWebKeyValueStorageManagerProxy>()
    246         || messageID.is<CoreIPC::MessageClassWebMediaCacheManagerProxy>()
    247         || messageID.is<CoreIPC::MessageClassWebResourceCacheManagerProxy>()) {
    248         m_context->didReceiveMessage(connection, messageID, arguments);
    249         return;
    250     }
    251 
    252     uint64_t pageID = arguments->destinationID();
    253     if (!pageID)
    254         return;
    255 
    256     WebPageProxy* pageProxy = webPage(pageID);
    257     if (!pageProxy)
    258         return;
    259 
    260     pageProxy->didReceiveMessage(connection, messageID, arguments);
    261 }
    262 
    263 CoreIPC::SyncReplyMode WebProcessProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply)
    264 {
    265     if (messageID.is<CoreIPC::MessageClassWebProcessProxy>())
    266         return didReceiveSyncWebProcessProxyMessage(connection, messageID, arguments, reply);
    267 
    268     if (messageID.is<CoreIPC::MessageClassWebContext>() || messageID.is<CoreIPC::MessageClassWebContextLegacy>()
    269         || messageID.is<CoreIPC::MessageClassDownloadProxy>() || messageID.is<CoreIPC::MessageClassWebIconDatabase>())
    270         return m_context->didReceiveSyncMessage(connection, messageID, arguments, reply);
    271 
    272     uint64_t pageID = arguments->destinationID();
    273     if (!pageID)
    274         return CoreIPC::AutomaticReply;
    275 
    276     WebPageProxy* pageProxy = webPage(pageID);
    277     if (!pageProxy)
    278         return CoreIPC::AutomaticReply;
    279 
    280     pageProxy->didReceiveSyncMessage(connection, messageID, arguments, reply);
    281     return CoreIPC::AutomaticReply;
    282 }
    283 
    284 void WebProcessProxy::didClose(CoreIPC::Connection*)
    285 {
    286     // Protect ourselves, as the call to disconnect() below may otherwise cause us
    287     // to be deleted before we can finish our work.
    288     RefPtr<WebProcessProxy> protect(this);
    289 
    290     Vector<RefPtr<WebPageProxy> > pages;
    291     copyValuesToVector(m_pageMap, pages);
    292 
    293     disconnect();
    294 
    295     for (size_t i = 0, size = pages.size(); i < size; ++i)
    296         pages[i]->processDidCrash();
    297 }
    298 
    299 void WebProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID)
    300 {
    301     // We received an invalid message from the web process, invalidate our connection and kill it.
    302     m_connection->invalidate();
    303 
    304     terminate();
    305 }
    306 
    307 void WebProcessProxy::syncMessageSendTimedOut(CoreIPC::Connection*)
    308 {
    309 }
    310 
    311 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*)
    312 {
    313     Vector<RefPtr<WebPageProxy> > pages;
    314     copyValuesToVector(m_pageMap, pages);
    315     for (size_t i = 0, size = pages.size(); i < size; ++i)
    316         pages[i]->processDidBecomeUnresponsive();
    317 }
    318 
    319 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*)
    320 {
    321     Vector<RefPtr<WebPageProxy> > pages;
    322     copyValuesToVector(m_pageMap, pages);
    323     for (size_t i = 0, size = pages.size(); i < size; ++i)
    324         pages[i]->processDidBecomeResponsive();
    325 }
    326 
    327 void WebProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
    328 {
    329     didFinishLaunching(connectionIdentifier);
    330 }
    331 
    332 void WebProcessProxy::didFinishLaunching(ThreadLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
    333 {
    334     didFinishLaunching(connectionIdentifier);
    335 }
    336 
    337 void WebProcessProxy::didFinishLaunching(CoreIPC::Connection::Identifier connectionIdentifier)
    338 {
    339     ASSERT(!m_connection);
    340 
    341     m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main());
    342 #if PLATFORM(MAC)
    343     m_connection->setShouldCloseConnectionOnMachExceptions();
    344 #elif PLATFORM(QT) || PLATFORM(GTK)
    345     m_connection->setShouldCloseConnectionOnProcessTermination(processIdentifier());
    346 #endif
    347 
    348     m_connection->open();
    349 
    350     for (size_t i = 0; i < m_pendingMessages.size(); ++i) {
    351         CoreIPC::Connection::OutgoingMessage& outgoingMessage = m_pendingMessages[i].first;
    352         unsigned messageSendFlags = m_pendingMessages[i].second;
    353         m_connection->sendMessage(outgoingMessage.messageID(), adoptPtr(outgoingMessage.arguments()), messageSendFlags);
    354     }
    355 
    356     m_pendingMessages.clear();
    357 
    358     // Tell the context that we finished launching.
    359     m_context->processDidFinishLaunching(this);
    360 }
    361 
    362 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
    363 {
    364     return isGoodKey<WebFrameProxyMap>(frameID) ? m_frameMap.get(frameID).get() : 0;
    365 }
    366 
    367 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
    368 {
    369     return isGoodKey<WebFrameProxyMap>(frameID) && !m_frameMap.contains(frameID);
    370 }
    371 
    372 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
    373 {
    374     ASSERT(canCreateFrame(frameID));
    375     m_frameMap.set(frameID, frameProxy);
    376 }
    377 
    378 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
    379 {
    380     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
    381     // back to the UIProcess, then the frameDestroyed message will still be received because it
    382     // gets sent directly to the WebProcessProxy.
    383     ASSERT(isGoodKey<WebFrameProxyMap>(frameID));
    384     m_frameMap.remove(frameID);
    385 }
    386 
    387 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
    388 {
    389     Vector<RefPtr<WebFrameProxy> > frames;
    390     copyValuesToVector(m_frameMap, frames);
    391     for (size_t i = 0, size = frames.size(); i < size; ++i) {
    392         if (frames[i]->page() == page)
    393             frames[i]->disconnect();
    394     }
    395 }
    396 
    397 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
    398 {
    399     size_t result = 0;
    400     for (HashMap<uint64_t, RefPtr<WebFrameProxy> >::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
    401         if (iter->second->page() == page)
    402             ++result;
    403     }
    404     return result;
    405 }
    406 
    407 void WebProcessProxy::shouldTerminate(bool& shouldTerminate)
    408 {
    409     if (!m_pageMap.isEmpty() || !m_context->shouldTerminate(this)) {
    410         shouldTerminate = false;
    411         return;
    412     }
    413 
    414     shouldTerminate = true;
    415 
    416     // We know that the web process is going to terminate so disconnect it from the context.
    417     disconnect();
    418 }
    419 
    420 void WebProcessProxy::updateTextCheckerState()
    421 {
    422     if (!isValid())
    423         return;
    424 
    425     send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
    426 }
    427 
    428 } // namespace WebKit
    429