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 "PluginProcess.h" 28 29#if ENABLE(NETSCAPE_PLUGIN_API) 30 31#include "ArgumentCoders.h" 32#include "Attachment.h" 33#include "NetscapePlugin.h" 34#include "NetscapePluginModule.h" 35#include "PluginProcessConnectionMessages.h" 36#include "PluginProcessCreationParameters.h" 37#include "PluginProcessProxyMessages.h" 38#include "WebProcessConnection.h" 39#include <WebCore/MemoryPressureHandler.h> 40#include <WebCore/NotImplemented.h> 41#include <wtf/RunLoop.h> 42 43#if PLATFORM(MAC) 44#include <crt_externs.h> 45#endif 46 47using namespace WebCore; 48 49namespace WebKit { 50 51PluginProcess& PluginProcess::shared() 52{ 53 static NeverDestroyed<PluginProcess> pluginProcess; 54 return pluginProcess; 55} 56 57PluginProcess::PluginProcess() 58 : m_supportsAsynchronousPluginInitialization(false) 59 , m_minimumLifetimeTimer(RunLoop::main(), this, &PluginProcess::minimumLifetimeTimerFired) 60#if PLATFORM(COCOA) 61 , m_compositingRenderServerPort(MACH_PORT_NULL) 62#endif 63 , m_connectionActivity("PluginProcess connection activity.") 64 , m_visiblePluginsActivity("Visible plugins from PluginProcess activity.") 65{ 66 NetscapePlugin::setSetExceptionFunction(WebProcessConnection::setGlobalException); 67 m_audioHardwareListener = AudioHardwareListener::create(*this); 68} 69 70PluginProcess::~PluginProcess() 71{ 72} 73 74void PluginProcess::lowMemoryHandler(bool critical) 75{ 76 UNUSED_PARAM(critical); 77 if (shared().shouldTerminate()) 78 shared().terminate(); 79} 80 81void PluginProcess::initializeProcess(const ChildProcessInitializationParameters& parameters) 82{ 83 m_pluginPath = parameters.extraInitializationData.get("plugin-path"); 84 platformInitializeProcess(parameters); 85 86 memoryPressureHandler().setLowMemoryHandler(lowMemoryHandler); 87 memoryPressureHandler().install(); 88} 89 90void PluginProcess::removeWebProcessConnection(WebProcessConnection* webProcessConnection) 91{ 92 size_t vectorIndex = m_webProcessConnections.find(webProcessConnection); 93 ASSERT(vectorIndex != notFound); 94 95 m_webProcessConnections.remove(vectorIndex); 96 97 if (m_webProcessConnections.isEmpty() && m_pluginModule) { 98 // Decrement the load count. This is balanced by a call to incrementLoadCount in createWebProcessConnection. 99 m_pluginModule->decrementLoadCount(); 100 } 101 102 enableTermination(); 103} 104 105NetscapePluginModule* PluginProcess::netscapePluginModule() 106{ 107 if (!m_pluginModule) { 108 ASSERT(!m_pluginPath.isNull()); 109 m_pluginModule = NetscapePluginModule::getOrCreate(m_pluginPath); 110 111#if PLATFORM(MAC) 112 if (m_pluginModule) { 113 if (m_pluginModule->pluginQuirks().contains(PluginQuirks::PrognameShouldBeWebKitPluginHost)) 114 *const_cast<const char**>(_NSGetProgname()) = "WebKitPluginHost"; 115 } 116#endif 117 } 118 119 return m_pluginModule.get(); 120} 121 122bool PluginProcess::shouldTerminate() 123{ 124 return m_webProcessConnections.isEmpty(); 125} 126 127void PluginProcess::didReceiveMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder) 128{ 129 didReceivePluginProcessMessage(connection, decoder); 130} 131 132void PluginProcess::didClose(IPC::Connection*) 133{ 134 // The UI process has crashed, just go ahead and quit. 135 // FIXME: If the plug-in is spinning in the main loop, we'll never get this message. 136 stopRunLoop(); 137} 138 139void PluginProcess::didReceiveInvalidMessage(IPC::Connection*, IPC::StringReference, IPC::StringReference) 140{ 141} 142 143void PluginProcess::initializePluginProcess(const PluginProcessCreationParameters& parameters) 144{ 145 ASSERT(!m_pluginModule); 146 147 m_supportsAsynchronousPluginInitialization = parameters.supportsAsynchronousPluginInitialization; 148 setMinimumLifetime(parameters.minimumLifetime); 149 setTerminationTimeout(parameters.terminationTimeout); 150 151 platformInitializePluginProcess(parameters); 152} 153 154void PluginProcess::createWebProcessConnection() 155{ 156 bool didHaveAnyWebProcessConnections = !m_webProcessConnections.isEmpty(); 157 158#if OS(DARWIN) 159 // Create the listening port. 160 mach_port_t listeningPort; 161 mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort); 162 163 // Create a listening connection. 164 RefPtr<WebProcessConnection> connection = WebProcessConnection::create(IPC::Connection::Identifier(listeningPort)); 165 166 if (m_audioHardwareListener) { 167 if (m_audioHardwareListener->hardwareActivity() == WebCore::AudioHardwareActivityType::IsActive) 168 connection->audioHardwareDidBecomeActive(); 169 else if (m_audioHardwareListener->hardwareActivity() == WebCore::AudioHardwareActivityType::IsInactive) 170 connection->audioHardwareDidBecomeInactive(); 171 } 172 173 m_webProcessConnections.append(connection.release()); 174 175 IPC::Attachment clientPort(listeningPort, MACH_MSG_TYPE_MAKE_SEND); 176 parentProcessConnection()->send(Messages::PluginProcessProxy::DidCreateWebProcessConnection(clientPort, m_supportsAsynchronousPluginInitialization), 0); 177#elif USE(UNIX_DOMAIN_SOCKETS) 178 IPC::Connection::SocketPair socketPair = IPC::Connection::createPlatformConnection(); 179 180 RefPtr<WebProcessConnection> connection = WebProcessConnection::create(socketPair.server); 181 m_webProcessConnections.append(connection.release()); 182 183 IPC::Attachment clientSocket(socketPair.client); 184 parentProcessConnection()->send(Messages::PluginProcessProxy::DidCreateWebProcessConnection(clientSocket, m_supportsAsynchronousPluginInitialization), 0); 185#else 186 notImplemented(); 187#endif 188 189 if (NetscapePluginModule* module = netscapePluginModule()) { 190 if (!didHaveAnyWebProcessConnections) { 191 // Increment the load count. This is matched by a call to decrementLoadCount in removeWebProcessConnection. 192 // We do this so that the plug-in module's NP_Shutdown won't be called until right before exiting. 193 module->incrementLoadCount(); 194 } 195 } 196 197 disableTermination(); 198} 199 200void PluginProcess::getSitesWithData(uint64_t callbackID) 201{ 202 Vector<String> sites; 203 if (NetscapePluginModule* module = netscapePluginModule()) 204 sites = module->sitesWithData(); 205 206 parentProcessConnection()->send(Messages::PluginProcessProxy::DidGetSitesWithData(sites, callbackID), 0); 207} 208 209void PluginProcess::clearSiteData(const Vector<String>& sites, uint64_t flags, uint64_t maxAgeInSeconds, uint64_t callbackID) 210{ 211 if (NetscapePluginModule* module = netscapePluginModule()) { 212 if (sites.isEmpty()) { 213 // Clear everything. 214 module->clearSiteData(String(), flags, maxAgeInSeconds); 215 } else { 216 for (size_t i = 0; i < sites.size(); ++i) 217 module->clearSiteData(sites[i], flags, maxAgeInSeconds); 218 } 219 } 220 221 parentProcessConnection()->send(Messages::PluginProcessProxy::DidClearSiteData(callbackID), 0); 222} 223 224void PluginProcess::setMinimumLifetime(double lifetime) 225{ 226 if (lifetime <= 0.0) 227 return; 228 229 disableTermination(); 230 231 m_minimumLifetimeTimer.startOneShot(lifetime); 232} 233 234void PluginProcess::minimumLifetimeTimerFired() 235{ 236 enableTermination(); 237} 238 239#if !PLATFORM(COCOA) 240void PluginProcess::initializeProcessName(const ChildProcessInitializationParameters&) 241{ 242} 243 244void PluginProcess::initializeSandbox(const ChildProcessInitializationParameters&, SandboxInitializationParameters&) 245{ 246} 247#endif 248 249void PluginProcess::pluginsForWebProcessDidBecomeVisible() 250{ 251 m_visiblePluginsActivity.increment(); 252} 253 254void PluginProcess::pluginsForWebProcessDidBecomeHidden() 255{ 256 m_visiblePluginsActivity.decrement(); 257} 258 259void PluginProcess::audioHardwareDidBecomeActive() 260{ 261 for (auto& connection : m_webProcessConnections) 262 connection->audioHardwareDidBecomeActive(); 263} 264 265void PluginProcess::audioHardwareDidBecomeInactive() 266{ 267 for (auto& connection : m_webProcessConnections) 268 connection->audioHardwareDidBecomeInactive(); 269} 270 271} // namespace WebKit 272 273#endif // ENABLE(NETSCAPE_PLUGIN_API) 274 275