10f58b9bb325243f38609449199300dfa6edf616
[WebKit-https.git] / Source / WebKit2 / UIProcess / Plugins / PluginProcessProxy.cpp
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 "WebContext.h"
35 #include "WebCoreArgumentCoders.h"
36 #include "WebPluginSiteDataManager.h"
37 #include "WebProcessMessages.h"
38 #include "WebProcessProxy.h"
39 #include <WebCore/NotImplemented.h>
40 #include <WebCore/RunLoop.h>
41
42 #if PLATFORM(MAC)
43 #include "MachPort.h"
44 #endif
45
46 using namespace WebCore;
47
48 namespace WebKit {
49
50 static const double minimumLifetime = 30 * 60;
51 static const double shutdownTimeout = 10 * 60;
52
53 PassRefPtr<PluginProcessProxy> PluginProcessProxy::create(PluginProcessManager* PluginProcessManager, const PluginModuleInfo& pluginInfo)
54 {
55     return adoptRef(new PluginProcessProxy(PluginProcessManager, pluginInfo));
56 }
57
58 PluginProcessProxy::PluginProcessProxy(PluginProcessManager* PluginProcessManager, const PluginModuleInfo& pluginInfo)
59     : m_pluginProcessManager(PluginProcessManager)
60     , m_pluginInfo(pluginInfo)
61     , m_numPendingConnectionRequests(0)
62 #if PLATFORM(MAC)
63     , m_modalWindowIsShowing(false)
64     , m_fullscreenWindowIsShowing(false)
65     , m_preFullscreenAppPresentationOptions(0)
66 #endif
67 {
68     ProcessLauncher::LaunchOptions launchOptions;
69     launchOptions.processType = ProcessLauncher::PluginProcess;
70
71     platformInitializeLaunchOptions(launchOptions, pluginInfo);
72
73     m_processLauncher = ProcessLauncher::create(this, launchOptions);
74 }
75
76 PluginProcessProxy::~PluginProcessProxy()
77 {
78 }
79
80 // Asks the plug-in process to create a new connection to a web process. The connection identifier will be 
81 // encoded in the given argument encoder and sent back to the connection of the given web process.
82 void PluginProcessProxy::getPluginProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
83 {
84     m_pendingConnectionReplies.append(reply);
85
86     if (m_processLauncher->isLaunching()) {
87         m_numPendingConnectionRequests++;
88         return;
89     }
90     
91     // Ask the plug-in process to create a connection. Since the plug-in can be waiting for a synchronous reply
92     // we need to make sure that this message is always processed, even when the plug-in is waiting for a synchronus reply.
93     m_connection->send(Messages::PluginProcess::CreateWebProcessConnection(), 0, CoreIPC::DispatchMessageEvenWhenWaitingForSyncReply);
94 }
95
96 void PluginProcessProxy::getSitesWithData(WebPluginSiteDataManager* webPluginSiteDataManager, uint64_t callbackID)
97 {
98     ASSERT(!m_pendingGetSitesReplies.contains(callbackID));
99     m_pendingGetSitesReplies.set(callbackID, webPluginSiteDataManager);
100
101     if (m_processLauncher->isLaunching()) {
102         m_pendingGetSitesRequests.append(callbackID);
103         return;
104     }
105
106     // Ask the plug-in process for the sites with data.
107     m_connection->send(Messages::PluginProcess::GetSitesWithData(callbackID), 0);
108 }
109
110 void PluginProcessProxy::clearSiteData(WebPluginSiteDataManager* webPluginSiteDataManager, const Vector<String>& sites, uint64_t flags, uint64_t maxAgeInSeconds, uint64_t callbackID)
111 {
112     ASSERT(!m_pendingClearSiteDataReplies.contains(callbackID));
113     m_pendingClearSiteDataReplies.set(callbackID, webPluginSiteDataManager);
114
115     if (m_processLauncher->isLaunching()) {
116         ClearSiteDataRequest request;
117         request.sites = sites;
118         request.flags = flags;
119         request.maxAgeInSeconds = maxAgeInSeconds;
120         request.callbackID = callbackID;
121         m_pendingClearSiteDataRequests.append(request);
122         return;
123     }
124
125     // Ask the plug-in process to clear the site data.
126     m_connection->send(Messages::PluginProcess::ClearSiteData(sites, flags, maxAgeInSeconds, callbackID), 0);
127 }
128
129 void PluginProcessProxy::terminate()
130 {
131      m_processLauncher->terminateProcess();
132 }
133
134 void 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 PLATFORM(MAC)
141         reply->send(CoreIPC::Attachment(0, MACH_MSG_TYPE_MOVE_SEND), false);
142 #elif USE(UNIX_DOMAIN_SOCKETS)
143         reply->send(CoreIPC::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
159 void PluginProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
160 {
161     didReceivePluginProcessProxyMessage(connection, messageID, arguments);
162 }
163
164 void PluginProcessProxy::didClose(CoreIPC::Connection*)
165 {
166 #if PLATFORM(MAC)
167     if (m_modalWindowIsShowing)
168         endModal();
169
170     if (m_fullscreenWindowIsShowing)
171         exitFullscreen();
172 #endif
173
174     const Vector<WebContext*>& contexts = WebContext::allContexts();
175     for (size_t i = 0; i < contexts.size(); ++i)
176         contexts[i]->sendToAllProcesses(Messages::WebProcess::PluginProcessCrashed(m_pluginInfo.path));
177
178     // This will cause us to be deleted.
179     pluginProcessCrashedOrFailedToLaunch();
180 }
181
182 void PluginProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID)
183 {
184 }
185
186 void PluginProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
187 {
188     ASSERT(!m_connection);
189
190     if (CoreIPC::Connection::identifierIsNull(connectionIdentifier)) {
191         pluginProcessCrashedOrFailedToLaunch();
192         return;
193     }
194
195     m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main());
196 #if PLATFORM(MAC)
197     m_connection->setShouldCloseConnectionOnMachExceptions();
198 #elif PLATFORM(QT)
199     m_connection->setShouldCloseConnectionOnProcessTermination(m_processLauncher->processIdentifier());
200 #endif
201
202     m_connection->open();
203     
204     PluginProcessCreationParameters parameters;
205
206     parameters.pluginPath = m_pluginInfo.path;
207
208     parameters.minimumLifetime = minimumLifetime;
209     parameters.terminationTimeout = shutdownTimeout;
210
211     platformInitializePluginProcess(parameters);
212
213     // Initialize the plug-in host process.
214     m_connection->send(Messages::PluginProcess::InitializePluginProcess(parameters), 0);
215
216     // Send all our pending requests.
217     for (size_t i = 0; i < m_pendingGetSitesRequests.size(); ++i)
218         m_connection->send(Messages::PluginProcess::GetSitesWithData(m_pendingGetSitesRequests[i]), 0);
219     m_pendingGetSitesRequests.clear();
220
221     for (size_t i = 0; i < m_pendingClearSiteDataRequests.size(); ++i) {
222         const ClearSiteDataRequest& request = m_pendingClearSiteDataRequests[i];
223         m_connection->send(Messages::PluginProcess::ClearSiteData(request.sites, request.flags, request.maxAgeInSeconds, request.callbackID), 0);
224     }
225     m_pendingClearSiteDataRequests.clear();
226
227     for (unsigned i = 0; i < m_numPendingConnectionRequests; ++i)
228         m_connection->send(Messages::PluginProcess::CreateWebProcessConnection(), 0);
229     
230     m_numPendingConnectionRequests = 0;
231 }
232
233 void PluginProcessProxy::didCreateWebProcessConnection(const CoreIPC::Attachment& connectionIdentifier, bool supportsAsynchronousPluginInitialization)
234 {
235     ASSERT(!m_pendingConnectionReplies.isEmpty());
236
237     // Grab the first pending connection reply.
238     RefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply = m_pendingConnectionReplies.takeFirst();
239
240 #if PLATFORM(MAC)
241     reply->send(CoreIPC::Attachment(connectionIdentifier.port(), MACH_MSG_TYPE_MOVE_SEND), supportsAsynchronousPluginInitialization);
242 #elif USE(UNIX_DOMAIN_SOCKETS)
243     reply->send(connectionIdentifier, supportsAsynchronousPluginInitialization);
244 #else
245     notImplemented();
246 #endif
247 }
248
249 void PluginProcessProxy::didGetSitesWithData(const Vector<String>& sites, uint64_t callbackID)
250 {
251     RefPtr<WebPluginSiteDataManager> webPluginSiteDataManager = m_pendingGetSitesReplies.take(callbackID);
252     ASSERT(webPluginSiteDataManager);
253
254     webPluginSiteDataManager->didGetSitesWithDataForSinglePlugin(sites, callbackID);
255 }
256
257 void PluginProcessProxy::didClearSiteData(uint64_t callbackID)
258 {
259     RefPtr<WebPluginSiteDataManager> webPluginSiteDataManager = m_pendingClearSiteDataReplies.take(callbackID);
260     ASSERT(webPluginSiteDataManager);
261     
262     webPluginSiteDataManager->didClearSiteDataForSinglePlugin(callbackID);
263 }
264
265 } // namespace WebKit
266
267 #endif // ENABLE(PLUGIN_PROCESS)