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