Home | History | Annotate | Download | only in Plugins
      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 "config.h"
     27 #include "PluginProcessProxy.h"
     28 
     29 #if ENABLE(PLUGIN_PROCESS)
     30 
     31 #include "PluginProcessCreationParameters.h"
     32 #include "PluginProcessManager.h"
     33 #include "PluginProcessMessages.h"
     34 #include "RunLoop.h"
     35 #include "WebCoreArgumentCoders.h"
     36 #include "WebPluginSiteDataManager.h"
     37 #include "WebProcessProxy.h"
     38 
     39 #if PLATFORM(MAC)
     40 #include "MachPort.h"
     41 #endif
     42 
     43 namespace WebKit {
     44 
     45 PassOwnPtr<PluginProcessProxy> PluginProcessProxy::create(PluginProcessManager* PluginProcessManager, const PluginInfoStore::Plugin& pluginInfo)
     46 {
     47     return adoptPtr(new PluginProcessProxy(PluginProcessManager, pluginInfo));
     48 }
     49 
     50 PluginProcessProxy::PluginProcessProxy(PluginProcessManager* PluginProcessManager, const PluginInfoStore::Plugin& pluginInfo)
     51     : m_pluginProcessManager(PluginProcessManager)
     52     , m_pluginInfo(pluginInfo)
     53     , m_numPendingConnectionRequests(0)
     54 #if PLATFORM(MAC)
     55     , m_modalWindowIsShowing(false)
     56     , m_fullscreenWindowIsShowing(false)
     57     , m_preFullscreenAppPresentationOptions(0)
     58 #endif
     59 {
     60     ProcessLauncher::LaunchOptions launchOptions;
     61     launchOptions.processType = ProcessLauncher::PluginProcess;
     62 #if PLATFORM(MAC)
     63     launchOptions.architecture = pluginInfo.pluginArchitecture;
     64     launchOptions.executableHeap = PluginProcessProxy::pluginNeedsExecutableHeap(pluginInfo);
     65 #endif
     66 
     67     m_processLauncher = ProcessLauncher::create(this, launchOptions);
     68 }
     69 
     70 PluginProcessProxy::~PluginProcessProxy()
     71 {
     72 }
     73 
     74 // Asks the plug-in process to create a new connection to a web process. The connection identifier will be
     75 // encoded in the given argument encoder and sent back to the connection of the given web process.
     76 void PluginProcessProxy::getPluginProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
     77 {
     78     m_pendingConnectionReplies.append(reply);
     79 
     80     if (m_processLauncher->isLaunching()) {
     81         m_numPendingConnectionRequests++;
     82         return;
     83     }
     84 
     85     // Ask the plug-in process to create a connection. Since the plug-in can be waiting for a synchronous reply
     86     // we need to make sure that this message is always processed, even when the plug-in is waiting for a synchronus reply.
     87     m_connection->send(Messages::PluginProcess::CreateWebProcessConnection(), 0, CoreIPC::DispatchMessageEvenWhenWaitingForSyncReply);
     88 }
     89 
     90 void PluginProcessProxy::getSitesWithData(WebPluginSiteDataManager* webPluginSiteDataManager, uint64_t callbackID)
     91 {
     92     ASSERT(!m_pendingGetSitesReplies.contains(callbackID));
     93     m_pendingGetSitesReplies.set(callbackID, webPluginSiteDataManager);
     94 
     95     if (m_processLauncher->isLaunching()) {
     96         m_pendingGetSitesRequests.append(callbackID);
     97         return;
     98     }
     99 
    100     // Ask the plug-in process for the sites with data.
    101     m_connection->send(Messages::PluginProcess::GetSitesWithData(callbackID), 0);
    102 }
    103 
    104 void PluginProcessProxy::clearSiteData(WebPluginSiteDataManager* webPluginSiteDataManager, const Vector<String>& sites, uint64_t flags, uint64_t maxAgeInSeconds, uint64_t callbackID)
    105 {
    106     ASSERT(!m_pendingClearSiteDataReplies.contains(callbackID));
    107     m_pendingClearSiteDataReplies.set(callbackID, webPluginSiteDataManager);
    108 
    109     if (m_processLauncher->isLaunching()) {
    110         ClearSiteDataRequest request;
    111         request.sites = sites;
    112         request.flags = flags;
    113         request.maxAgeInSeconds = maxAgeInSeconds;
    114         request.callbackID = callbackID;
    115         m_pendingClearSiteDataRequests.append(request);
    116         return;
    117     }
    118 
    119     // Ask the plug-in process to clear the site data.
    120     m_connection->send(Messages::PluginProcess::ClearSiteData(sites, flags, maxAgeInSeconds, callbackID), 0);
    121 }
    122 
    123 void PluginProcessProxy::terminate()
    124 {
    125      m_processLauncher->terminateProcess();
    126 }
    127 
    128 void PluginProcessProxy::pluginProcessCrashedOrFailedToLaunch()
    129 {
    130     // The plug-in process must have crashed or exited, send any pending sync replies we might have.
    131     while (!m_pendingConnectionReplies.isEmpty()) {
    132         RefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply = m_pendingConnectionReplies.takeFirst();
    133 
    134 #if PLATFORM(MAC)
    135         reply->send(CoreIPC::MachPort(0, MACH_MSG_TYPE_MOVE_SEND));
    136 #else
    137         // FIXME: Implement.
    138         ASSERT_NOT_REACHED();
    139 #endif
    140     }
    141 
    142     while (!m_pendingGetSitesReplies.isEmpty())
    143         didGetSitesWithData(Vector<String>(), m_pendingGetSitesReplies.begin()->first);
    144 
    145     while (!m_pendingClearSiteDataReplies.isEmpty())
    146         didClearSiteData(m_pendingClearSiteDataReplies.begin()->first);
    147 
    148     // Tell the plug-in process manager to forget about this plug-in process proxy.
    149     m_pluginProcessManager->removePluginProcessProxy(this);
    150     delete this;
    151 }
    152 
    153 void PluginProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
    154 {
    155     didReceivePluginProcessProxyMessage(connection, messageID, arguments);
    156 }
    157 
    158 void PluginProcessProxy::didClose(CoreIPC::Connection*)
    159 {
    160 #if PLATFORM(MAC)
    161     if (m_modalWindowIsShowing)
    162         endModal();
    163 
    164     if (m_fullscreenWindowIsShowing)
    165         exitFullscreen();
    166 #endif
    167 
    168     pluginProcessCrashedOrFailedToLaunch();
    169 }
    170 
    171 void PluginProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID)
    172 {
    173 }
    174 
    175 void PluginProcessProxy::syncMessageSendTimedOut(CoreIPC::Connection*)
    176 {
    177 }
    178 
    179 void PluginProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
    180 {
    181     ASSERT(!m_connection);
    182 
    183     if (!connectionIdentifier) {
    184         pluginProcessCrashedOrFailedToLaunch();
    185         return;
    186     }
    187 
    188     m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main());
    189     m_connection->open();
    190 
    191     PluginProcessCreationParameters parameters;
    192 
    193     parameters.pluginPath = m_pluginInfo.path;
    194 
    195     platformInitializePluginProcess(parameters);
    196 
    197     // Initialize the plug-in host process.
    198     m_connection->send(Messages::PluginProcess::InitializePluginProcess(parameters), 0);
    199 
    200     // Send all our pending requests.
    201     for (size_t i = 0; i < m_pendingGetSitesRequests.size(); ++i)
    202         m_connection->send(Messages::PluginProcess::GetSitesWithData(m_pendingGetSitesRequests[i]), 0);
    203     m_pendingGetSitesRequests.clear();
    204 
    205     for (size_t i = 0; i < m_pendingClearSiteDataRequests.size(); ++i) {
    206         const ClearSiteDataRequest& request = m_pendingClearSiteDataRequests[i];
    207         m_connection->send(Messages::PluginProcess::ClearSiteData(request.sites, request.flags, request.maxAgeInSeconds, request.callbackID), 0);
    208     }
    209     m_pendingClearSiteDataRequests.clear();
    210 
    211     for (unsigned i = 0; i < m_numPendingConnectionRequests; ++i)
    212         m_connection->send(Messages::PluginProcess::CreateWebProcessConnection(), 0);
    213 
    214     m_numPendingConnectionRequests = 0;
    215 }
    216 
    217 #if PLATFORM(MAC)
    218 void PluginProcessProxy::didCreateWebProcessConnection(const CoreIPC::MachPort& machPort)
    219 {
    220     ASSERT(!m_pendingConnectionReplies.isEmpty());
    221 
    222     // Grab the first pending connection reply.
    223     RefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply = m_pendingConnectionReplies.takeFirst();
    224 
    225     reply->send(CoreIPC::MachPort(machPort.port(), MACH_MSG_TYPE_MOVE_SEND));
    226 }
    227 #endif
    228 
    229 void PluginProcessProxy::didGetSitesWithData(const Vector<String>& sites, uint64_t callbackID)
    230 {
    231     RefPtr<WebPluginSiteDataManager> webPluginSiteDataManager = m_pendingGetSitesReplies.take(callbackID);
    232     ASSERT(webPluginSiteDataManager);
    233 
    234     webPluginSiteDataManager->didGetSitesWithDataForSinglePlugin(sites, callbackID);
    235 }
    236 
    237 void PluginProcessProxy::didClearSiteData(uint64_t callbackID)
    238 {
    239     RefPtr<WebPluginSiteDataManager> webPluginSiteDataManager = m_pendingClearSiteDataReplies.take(callbackID);
    240     ASSERT(webPluginSiteDataManager);
    241 
    242     webPluginSiteDataManager->didClearSiteDataForSinglePlugin(callbackID);
    243 }
    244 
    245 } // namespace WebKit
    246 
    247 #endif // ENABLE(PLUGIN_PROCESS)
    248