186a7cbf46696787e72f3f69504b10887724d0dc
[WebKit-https.git] / Source / WebKit2 / PluginProcess / WebProcessConnection.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 "WebProcessConnection.h"
28
29 #if ENABLE(NETSCAPE_PLUGIN_API)
30
31 #include "ActivityAssertion.h"
32 #include "ArgumentCoders.h"
33 #include "ConnectionStack.h"
34 #include "NPObjectMessageReceiverMessages.h"
35 #include "NPRemoteObjectMap.h"
36 #include "PluginControllerProxy.h"
37 #include "PluginCreationParameters.h"
38 #include "PluginProcess.h"
39 #include "PluginProcessConnectionMessages.h"
40 #include "PluginProxyMessages.h"
41 #include "WebProcessConnectionMessages.h"
42 #include <WebCore/AudioHardwareListener.h>
43 #include <unistd.h>
44 #include <wtf/RunLoop.h>
45
46 using namespace WebCore;
47
48 namespace WebKit {
49
50 PassRefPtr<WebProcessConnection> WebProcessConnection::create(IPC::Connection::Identifier connectionIdentifier)
51 {
52     return adoptRef(new WebProcessConnection(connectionIdentifier));
53 }
54
55 WebProcessConnection::~WebProcessConnection()
56 {
57     ASSERT(m_pluginControllers.isEmpty());
58     ASSERT(!m_npRemoteObjectMap);
59     ASSERT(!m_connection);
60 }
61     
62 WebProcessConnection::WebProcessConnection(IPC::Connection::Identifier connectionIdentifier)
63 {
64     m_connection = IPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main());
65     m_npRemoteObjectMap = NPRemoteObjectMap::create(m_connection.get());
66
67     m_connection->setOnlySendMessagesAsDispatchWhenWaitingForSyncReplyWhenProcessingSuchAMessage(true);
68     m_connection->open();
69 }
70
71 void WebProcessConnection::addPluginControllerProxy(std::unique_ptr<PluginControllerProxy> pluginController)
72 {
73     uint64_t pluginInstanceID = pluginController->pluginInstanceID();
74
75     ASSERT(!m_pluginControllers.contains(pluginInstanceID));
76     m_pluginControllers.set(pluginInstanceID, WTF::move(pluginController));
77 }
78
79 void WebProcessConnection::destroyPluginControllerProxy(PluginControllerProxy* pluginController)
80 {
81     // This may end up calling removePluginControllerProxy which ends up deleting
82     // the WebProcessConnection object if this was the last object.
83     pluginController->destroy();
84 }
85
86 void WebProcessConnection::removePluginControllerProxy(PluginControllerProxy* pluginController, Plugin* plugin)
87 {
88     unsigned pluginInstanceID = pluginController->pluginInstanceID();
89     {
90         ASSERT(m_pluginControllers.contains(pluginInstanceID));
91
92         std::unique_ptr<PluginControllerProxy> pluginControllerUniquePtr = m_pluginControllers.take(pluginInstanceID);
93         ASSERT(pluginControllerUniquePtr.get() == pluginController);
94     }
95
96     // Invalidate all objects related to this plug-in.
97     if (plugin)
98         m_npRemoteObjectMap->pluginDestroyed(plugin);
99
100     if (!m_pluginControllers.isEmpty())
101         return;
102
103     m_npRemoteObjectMap = nullptr;
104
105     // The last plug-in went away, close this connection.
106     m_connection->invalidate();
107     m_connection = nullptr;
108
109     // This will cause us to be deleted.    
110     PluginProcess::shared().removeWebProcessConnection(this);
111 }
112
113 void WebProcessConnection::setGlobalException(const String& exceptionString)
114 {
115     IPC::Connection* connection = ConnectionStack::shared().current();
116     if (!connection)
117         return;
118
119     connection->sendSync(Messages::PluginProcessConnection::SetException(exceptionString), Messages::PluginProcessConnection::SetException::Reply(), 0);
120 }
121
122 void WebProcessConnection::didReceiveMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder)
123 {
124     ConnectionStack::CurrentConnectionPusher currentConnection(ConnectionStack::shared(), connection);
125
126     if (decoder.messageReceiverName() == Messages::WebProcessConnection::messageReceiverName()) {
127         didReceiveWebProcessConnectionMessage(connection, decoder);
128         return;
129     }
130
131     if (!decoder.destinationID()) {
132         ASSERT_NOT_REACHED();
133         return;
134     }
135
136     PluginControllerProxy* pluginControllerProxy = m_pluginControllers.get(decoder.destinationID());
137     if (!pluginControllerProxy)
138         return;
139
140     PluginController::PluginDestructionProtector protector(pluginControllerProxy->asPluginController());
141     pluginControllerProxy->didReceivePluginControllerProxyMessage(connection, decoder);
142 }
143
144 void WebProcessConnection::didReceiveSyncMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
145 {
146     ConnectionStack::CurrentConnectionPusher currentConnection(ConnectionStack::shared(), connection);
147
148     uint64_t destinationID = decoder.destinationID();
149
150     if (!destinationID) {
151         didReceiveSyncWebProcessConnectionMessage(connection, decoder, replyEncoder);
152         return;
153     }
154
155     if (decoder.messageReceiverName() == Messages::NPObjectMessageReceiver::messageReceiverName()) {
156         m_npRemoteObjectMap->didReceiveSyncMessage(connection, decoder, replyEncoder);
157         return;
158     }
159
160     PluginControllerProxy* pluginControllerProxy = m_pluginControllers.get(decoder.destinationID());
161     if (!pluginControllerProxy)
162         return;
163
164     PluginController::PluginDestructionProtector protector(pluginControllerProxy->asPluginController());
165     pluginControllerProxy->didReceiveSyncPluginControllerProxyMessage(connection, decoder, replyEncoder);
166 }
167
168 void WebProcessConnection::didClose(IPC::Connection*)
169 {
170     // The web process crashed. Destroy all the plug-in controllers. Destroying the last plug-in controller
171     // will cause the web process connection itself to be destroyed.
172     Vector<PluginControllerProxy*> pluginControllers;
173     for (auto it = m_pluginControllers.values().begin(), end = m_pluginControllers.values().end(); it != end; ++it)
174         pluginControllers.append(it->get());
175
176     for (size_t i = 0; i < pluginControllers.size(); ++i)
177         destroyPluginControllerProxy(pluginControllers[i]);
178 }
179
180 void WebProcessConnection::destroyPlugin(uint64_t pluginInstanceID, bool asynchronousCreationIncomplete, PassRefPtr<Messages::WebProcessConnection::DestroyPlugin::DelayedReply> reply)
181 {
182     // We return immediately from this synchronous IPC. We want to make sure the plugin destruction is just about to start so audio playback
183     // will finish soon after returning. However we don't want to wait for destruction to complete fully as that may take a while.
184     reply->send();
185
186     // Ensure we don't clamp any timers during destruction
187     ActivityAssertion activityAssertion(PluginProcess::shared().connectionActivity());
188
189     PluginControllerProxy* pluginControllerProxy = m_pluginControllers.get(pluginInstanceID);
190     
191     // If there is no PluginControllerProxy then this plug-in doesn't exist yet and we probably have nothing to do.
192     if (!pluginControllerProxy) {
193         // If the plugin we're supposed to destroy was requested asynchronously and doesn't exist yet,
194         // we need to flag the instance ID so it is not created later.
195         if (asynchronousCreationIncomplete)
196             m_asynchronousInstanceIDsToIgnore.add(pluginInstanceID);
197         
198         return;
199     }
200     
201     destroyPluginControllerProxy(pluginControllerProxy);
202 }
203
204 void WebProcessConnection::didReceiveInvalidMessage(IPC::Connection*, IPC::StringReference, IPC::StringReference)
205 {
206     // FIXME: Implement.
207 }
208
209 void WebProcessConnection::createPluginInternal(const PluginCreationParameters& creationParameters, bool& result, bool& wantsWheelEvents, uint32_t& remoteLayerClientID)
210 {
211     auto pluginControllerProxy = std::make_unique<PluginControllerProxy>(this, creationParameters);
212
213     PluginControllerProxy* pluginControllerProxyPtr = pluginControllerProxy.get();
214
215     // Make sure to add the proxy to the map before initializing it, since the plug-in might call out to the web process from 
216     // its NPP_New function. This will hand over ownership of the proxy to the web process connection.
217     addPluginControllerProxy(WTF::move(pluginControllerProxy));
218
219     // Now try to initialize the plug-in.
220     result = pluginControllerProxyPtr->initialize(creationParameters);
221
222     if (!result)
223         return;
224
225     wantsWheelEvents = pluginControllerProxyPtr->wantsWheelEvents();
226 #if PLATFORM(COCOA)
227     remoteLayerClientID = pluginControllerProxyPtr->remoteLayerClientID();
228 #else
229     UNUSED_PARAM(remoteLayerClientID);
230 #endif
231 }
232
233 void WebProcessConnection::createPlugin(const PluginCreationParameters& creationParameters, PassRefPtr<Messages::WebProcessConnection::CreatePlugin::DelayedReply> reply)
234 {
235     // Ensure we don't clamp any timers during initialization
236     ActivityAssertion activityAssertion(PluginProcess::shared().connectionActivity());
237
238     PluginControllerProxy* pluginControllerProxy = m_pluginControllers.get(creationParameters.pluginInstanceID);
239
240     // The controller proxy for the plug-in we're being asked to create synchronously might already exist if it was requested asynchronously before.
241     if (pluginControllerProxy) {
242         // It might still be in the middle of initialization in which case we have to let that initialization complete and respond to this message later.
243         if (pluginControllerProxy->isInitializing()) {
244             pluginControllerProxy->setInitializationReply(reply);
245             return;
246         }
247         
248         // If its initialization is complete then we need to respond to this message with the correct information about its creation.
249 #if PLATFORM(COCOA)
250         reply->send(true, pluginControllerProxy->wantsWheelEvents(), pluginControllerProxy->remoteLayerClientID());
251 #else
252         reply->send(true, pluginControllerProxy->wantsWheelEvents(), 0);
253 #endif
254         return;
255     }
256     
257     // The plugin we're supposed to create might have been requested asynchronously before.
258     // In that case we need to create it synchronously now but flag the instance ID so we don't recreate it asynchronously later.
259     if (creationParameters.asynchronousCreationIncomplete)
260         m_asynchronousInstanceIDsToIgnore.add(creationParameters.pluginInstanceID);
261     
262     bool result = false;
263     bool wantsWheelEvents = false;
264     uint32_t remoteLayerClientID = 0;
265     createPluginInternal(creationParameters, result, wantsWheelEvents, remoteLayerClientID);
266     
267     reply->send(result, wantsWheelEvents, remoteLayerClientID);
268 }
269
270 void WebProcessConnection::createPluginAsynchronously(const PluginCreationParameters& creationParameters)
271 {
272     // In the time since this plugin was requested asynchronously we might have created it synchronously or destroyed it.
273     // In either of those cases we need to ignore this creation request.
274     if (m_asynchronousInstanceIDsToIgnore.contains(creationParameters.pluginInstanceID)) {
275         m_asynchronousInstanceIDsToIgnore.remove(creationParameters.pluginInstanceID);
276         return;
277     }
278     
279     // This version of CreatePlugin is only used by plug-ins that are known to behave when started asynchronously.
280     bool result = false;
281     bool wantsWheelEvents = false;
282     uint32_t remoteLayerClientID = 0;
283     
284     if (creationParameters.artificialPluginInitializationDelayEnabled) {
285         unsigned artificialPluginInitializationDelay = 5;
286         sleep(artificialPluginInitializationDelay);
287     }
288
289     // Since plug-in creation can often message to the WebProcess synchronously (with NPP_Evaluate for example)
290     // we need to make sure that the web process will handle the plug-in process's synchronous messages,
291     // even if the web process is waiting on a synchronous reply itself.
292     // Normally the plug-in process doesn't give its synchronous messages the special flag to allow for that.
293     // We can force it to do so by incrementing the "DispatchMessageMarkedDispatchWhenWaitingForSyncReply" count.
294     m_connection->incrementDispatchMessageMarkedDispatchWhenWaitingForSyncReplyCount();
295
296     // The call to createPluginInternal can potentially cause the plug-in to be destroyed and
297     // thus free the WebProcessConnection object. Protect it.
298     Ref<WebProcessConnection> protect(*this);
299     createPluginInternal(creationParameters, result, wantsWheelEvents, remoteLayerClientID);
300
301     if (!m_connection) {
302         // createPluginInternal caused the connection to go away.
303         return;
304     }
305
306     m_connection->decrementDispatchMessageMarkedDispatchWhenWaitingForSyncReplyCount();
307
308     // If someone asked for this plug-in synchronously while it was in the middle of being created then we need perform the
309     // synchronous reply instead of sending the asynchronous reply.
310     PluginControllerProxy* pluginControllerProxy = m_pluginControllers.get(creationParameters.pluginInstanceID);
311     ASSERT(pluginControllerProxy);
312     if (RefPtr<Messages::WebProcessConnection::CreatePlugin::DelayedReply> delayedSyncReply = pluginControllerProxy->takeInitializationReply()) {
313         delayedSyncReply->send(result, wantsWheelEvents, remoteLayerClientID);
314         return;
315     }
316
317     // Otherwise, send the asynchronous results now.
318     if (!result) {
319         m_connection->sendSync(Messages::PluginProxy::DidFailToCreatePlugin(), Messages::PluginProxy::DidFailToCreatePlugin::Reply(), creationParameters.pluginInstanceID);
320         return;
321     }
322
323     m_connection->sendSync(Messages::PluginProxy::DidCreatePlugin(wantsWheelEvents, remoteLayerClientID), Messages::PluginProxy::DidCreatePlugin::Reply(), creationParameters.pluginInstanceID);
324 }
325     
326 void WebProcessConnection::audioHardwareDidBecomeActive()
327 {
328     m_connection->send(Messages::PluginProcessConnection::AudioHardwareDidBecomeActive(), 0);
329 }
330
331 void WebProcessConnection::audioHardwareDidBecomeInactive()
332 {
333     m_connection->send(Messages::PluginProcessConnection::AudioHardwareDidBecomeInactive(), 0);
334 }
335     
336 } // namespace WebKit
337
338 #endif // ENABLE(NETSCAPE_PLUGIN_API)