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(NETSCAPE_PLUGIN_API) 30 31#include "PluginProcessConnectionManagerMessages.h" 32#include "PluginProcessCreationParameters.h" 33#include "PluginProcessManager.h" 34#include "PluginProcessMessages.h" 35#include "WebContext.h" 36#include "WebCoreArgumentCoders.h" 37#include "WebPluginSiteDataManager.h" 38#include "WebProcessProxy.h" 39#include <WebCore/NotImplemented.h> 40#include <wtf/RunLoop.h> 41 42#if OS(DARWIN) 43#include "MachPort.h" 44#endif 45 46using namespace WebCore; 47 48namespace WebKit { 49 50static const double minimumLifetime = 2 * 60; 51static const double snapshottingMinimumLifetime = 30; 52 53static const double shutdownTimeout = 1 * 60; 54static const double snapshottingShutdownTimeout = 15; 55 56PassRefPtr<PluginProcessProxy> PluginProcessProxy::create(PluginProcessManager* PluginProcessManager, const PluginProcessAttributes& pluginProcessAttributes, uint64_t pluginProcessToken) 57{ 58 return adoptRef(new PluginProcessProxy(PluginProcessManager, pluginProcessAttributes, pluginProcessToken)); 59} 60 61PluginProcessProxy::PluginProcessProxy(PluginProcessManager* PluginProcessManager, const PluginProcessAttributes& pluginProcessAttributes, uint64_t pluginProcessToken) 62 : m_pluginProcessManager(PluginProcessManager) 63 , m_pluginProcessAttributes(pluginProcessAttributes) 64 , m_pluginProcessToken(pluginProcessToken) 65 , m_numPendingConnectionRequests(0) 66#if PLATFORM(COCOA) 67 , m_modalWindowIsShowing(false) 68 , m_fullscreenWindowIsShowing(false) 69 , m_preFullscreenAppPresentationOptions(0) 70#endif 71{ 72 connect(); 73} 74 75PluginProcessProxy::~PluginProcessProxy() 76{ 77} 78 79void PluginProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions) 80{ 81 launchOptions.processType = ProcessLauncher::PluginProcess; 82 platformGetLaunchOptions(launchOptions, m_pluginProcessAttributes); 83} 84 85// Asks the plug-in process to create a new connection to a web process. The connection identifier will be 86// encoded in the given argument encoder and sent back to the connection of the given web process. 87void PluginProcessProxy::getPluginProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply) 88{ 89 m_pendingConnectionReplies.append(reply); 90 91 if (state() == State::Launching) { 92 m_numPendingConnectionRequests++; 93 return; 94 } 95 96 // Ask the plug-in process to create a connection. Since the plug-in can be waiting for a synchronous reply 97 // we need to make sure that this message is always processed, even when the plug-in is waiting for a synchronus reply. 98 m_connection->send(Messages::PluginProcess::CreateWebProcessConnection(), 0, IPC::DispatchMessageEvenWhenWaitingForSyncReply); 99} 100 101void PluginProcessProxy::getSitesWithData(WebPluginSiteDataManager* webPluginSiteDataManager, uint64_t callbackID) 102{ 103 ASSERT(!m_pendingGetSitesReplies.contains(callbackID)); 104 m_pendingGetSitesReplies.set(callbackID, webPluginSiteDataManager); 105 106 if (state() == State::Launching) { 107 m_pendingGetSitesRequests.append(callbackID); 108 return; 109 } 110 111 // Ask the plug-in process for the sites with data. 112 m_connection->send(Messages::PluginProcess::GetSitesWithData(callbackID), 0); 113} 114 115void PluginProcessProxy::clearSiteData(WebPluginSiteDataManager* webPluginSiteDataManager, const Vector<String>& sites, uint64_t flags, uint64_t maxAgeInSeconds, uint64_t callbackID) 116{ 117 ASSERT(!m_pendingClearSiteDataReplies.contains(callbackID)); 118 m_pendingClearSiteDataReplies.set(callbackID, webPluginSiteDataManager); 119 120 if (state() == State::Launching) { 121 ClearSiteDataRequest request; 122 request.sites = sites; 123 request.flags = flags; 124 request.maxAgeInSeconds = maxAgeInSeconds; 125 request.callbackID = callbackID; 126 m_pendingClearSiteDataRequests.append(request); 127 return; 128 } 129 130 // Ask the plug-in process to clear the site data. 131 m_connection->send(Messages::PluginProcess::ClearSiteData(sites, flags, maxAgeInSeconds, callbackID), 0); 132} 133 134void PluginProcessProxy::pluginProcessCrashedOrFailedToLaunch() 135{ 136 // The plug-in process must have crashed or exited, send any pending sync replies we might have. 137 while (!m_pendingConnectionReplies.isEmpty()) { 138 RefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply = m_pendingConnectionReplies.takeFirst(); 139 140#if OS(DARWIN) 141 reply->send(IPC::Attachment(0, MACH_MSG_TYPE_MOVE_SEND), false); 142#elif USE(UNIX_DOMAIN_SOCKETS) 143 reply->send(IPC::Attachment(), false); 144#else 145 notImplemented(); 146#endif 147 } 148 149 while (!m_pendingGetSitesReplies.isEmpty()) 150 didGetSitesWithData(Vector<String>(), m_pendingGetSitesReplies.begin()->key); 151 152 while (!m_pendingClearSiteDataReplies.isEmpty()) 153 didClearSiteData(m_pendingClearSiteDataReplies.begin()->key); 154 155 // Tell the plug-in process manager to forget about this plug-in process proxy. This may cause us to be deleted. 156 m_pluginProcessManager->removePluginProcessProxy(this); 157} 158 159void PluginProcessProxy::didClose(IPC::Connection*) 160{ 161#if PLATFORM(COCOA) 162 if (m_modalWindowIsShowing) 163 endModal(); 164 165 if (m_fullscreenWindowIsShowing) 166 exitFullscreen(); 167#endif 168 169 const Vector<WebContext*>& contexts = WebContext::allContexts(); 170 for (size_t i = 0; i < contexts.size(); ++i) 171 contexts[i]->sendToAllProcesses(Messages::PluginProcessConnectionManager::PluginProcessCrashed(m_pluginProcessToken)); 172 173 // This will cause us to be deleted. 174 pluginProcessCrashedOrFailedToLaunch(); 175} 176 177void PluginProcessProxy::didReceiveInvalidMessage(IPC::Connection*, IPC::StringReference, IPC::StringReference) 178{ 179} 180 181void PluginProcessProxy::didFinishLaunching(ProcessLauncher*, IPC::Connection::Identifier connectionIdentifier) 182{ 183 ASSERT(!m_connection); 184 185 if (IPC::Connection::identifierIsNull(connectionIdentifier)) { 186 pluginProcessCrashedOrFailedToLaunch(); 187 return; 188 } 189 190 m_connection = IPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main()); 191#if PLATFORM(MAC) 192 m_connection->setShouldCloseConnectionOnMachExceptions(); 193#endif 194 195 m_connection->open(); 196 197 PluginProcessCreationParameters parameters; 198 parameters.processType = m_pluginProcessAttributes.processType; 199 if (parameters.processType == PluginProcessTypeSnapshot) { 200 parameters.minimumLifetime = snapshottingMinimumLifetime; 201 parameters.terminationTimeout = snapshottingShutdownTimeout; 202 } else { 203 parameters.minimumLifetime = minimumLifetime; 204 parameters.terminationTimeout = shutdownTimeout; 205 } 206 platformInitializePluginProcess(parameters); 207 208 // Initialize the plug-in host process. 209 m_connection->send(Messages::PluginProcess::InitializePluginProcess(parameters), 0); 210 211#if PLATFORM(COCOA) 212 m_connection->send(Messages::PluginProcess::SetQOS(pluginProcessLatencyQOS(), pluginProcessThroughputQOS()), 0); 213#endif 214 215 // Send all our pending requests. 216 for (size_t i = 0; i < m_pendingGetSitesRequests.size(); ++i) 217 m_connection->send(Messages::PluginProcess::GetSitesWithData(m_pendingGetSitesRequests[i]), 0); 218 m_pendingGetSitesRequests.clear(); 219 220 for (size_t i = 0; i < m_pendingClearSiteDataRequests.size(); ++i) { 221 const ClearSiteDataRequest& request = m_pendingClearSiteDataRequests[i]; 222 m_connection->send(Messages::PluginProcess::ClearSiteData(request.sites, request.flags, request.maxAgeInSeconds, request.callbackID), 0); 223 } 224 m_pendingClearSiteDataRequests.clear(); 225 226 for (unsigned i = 0; i < m_numPendingConnectionRequests; ++i) 227 m_connection->send(Messages::PluginProcess::CreateWebProcessConnection(), 0); 228 229 m_numPendingConnectionRequests = 0; 230 231#if PLATFORM(COCOA) 232 if (WebContext::processSuppressionIsEnabledForAllContexts()) 233 setProcessSuppressionEnabled(true); 234#endif 235} 236 237void PluginProcessProxy::didCreateWebProcessConnection(const IPC::Attachment& connectionIdentifier, bool supportsAsynchronousPluginInitialization) 238{ 239 ASSERT(!m_pendingConnectionReplies.isEmpty()); 240 241 // Grab the first pending connection reply. 242 RefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply = m_pendingConnectionReplies.takeFirst(); 243 244#if OS(DARWIN) 245 reply->send(IPC::Attachment(connectionIdentifier.port(), MACH_MSG_TYPE_MOVE_SEND), supportsAsynchronousPluginInitialization); 246#elif USE(UNIX_DOMAIN_SOCKETS) 247 reply->send(connectionIdentifier, supportsAsynchronousPluginInitialization); 248#else 249 notImplemented(); 250#endif 251} 252 253void PluginProcessProxy::didGetSitesWithData(const Vector<String>& sites, uint64_t callbackID) 254{ 255 RefPtr<WebPluginSiteDataManager> webPluginSiteDataManager = m_pendingGetSitesReplies.take(callbackID); 256 ASSERT(webPluginSiteDataManager); 257 258 webPluginSiteDataManager->didGetSitesWithDataForSinglePlugin(sites, callbackID); 259} 260 261void PluginProcessProxy::didClearSiteData(uint64_t callbackID) 262{ 263 RefPtr<WebPluginSiteDataManager> webPluginSiteDataManager = m_pendingClearSiteDataReplies.take(callbackID); 264 ASSERT(webPluginSiteDataManager); 265 266 webPluginSiteDataManager->didClearSiteDataForSinglePlugin(callbackID); 267} 268 269} // namespace WebKit 270 271#endif // ENABLE(NETSCAPE_PLUGIN_API) 272