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