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 43namespace WebKit { 44 45PassOwnPtr<PluginProcessProxy> PluginProcessProxy::create(PluginProcessManager* PluginProcessManager, const PluginInfoStore::Plugin& pluginInfo) 46{ 47 return adoptPtr(new PluginProcessProxy(PluginProcessManager, pluginInfo)); 48} 49 50PluginProcessProxy::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 70PluginProcessProxy::~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. 76void 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 90void 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 104void 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 123void PluginProcessProxy::terminate() 124{ 125 m_processLauncher->terminateProcess(); 126} 127 128void 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 153void PluginProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments) 154{ 155 didReceivePluginProcessProxyMessage(connection, messageID, arguments); 156} 157 158void 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 171void PluginProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID) 172{ 173} 174 175void PluginProcessProxy::syncMessageSendTimedOut(CoreIPC::Connection*) 176{ 177} 178 179void 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) 218void 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 229void 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 237void 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