2011-02-13 Anders Carlsson <andersca@apple.com>
[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 "MachPort.h"
32 #include "PluginProcessCreationParameters.h"
33 #include "PluginProcessManager.h"
34 #include "PluginProcessMessages.h"
35 #include "RunLoop.h"
36 #include "WebCoreArgumentCoders.h"
37 #include "WebProcessProxy.h"
38
39 namespace WebKit {
40
41 PassOwnPtr<PluginProcessProxy> PluginProcessProxy::create(PluginProcessManager* PluginProcessManager, const PluginInfoStore::Plugin& pluginInfo)
42 {
43     return adoptPtr(new PluginProcessProxy(PluginProcessManager, pluginInfo));
44 }
45
46 PluginProcessProxy::PluginProcessProxy(PluginProcessManager* PluginProcessManager, const PluginInfoStore::Plugin& pluginInfo)
47     : m_pluginProcessManager(PluginProcessManager)
48     , m_pluginInfo(pluginInfo)
49     , m_numPendingConnectionRequests(0)
50 {
51     ProcessLauncher::LaunchOptions launchOptions;
52     launchOptions.processType = ProcessLauncher::PluginProcess;
53 #if PLATFORM(MAC)
54     launchOptions.architecture = pluginInfo.pluginArchitecture;
55
56     // FIXME: This shouldn't be true for all plug-ins.
57     launchOptions.executableHeap = true;
58 #endif
59
60     m_processLauncher = ProcessLauncher::create(this, launchOptions);
61 }
62
63 PluginProcessProxy::~PluginProcessProxy()
64 {
65 }
66
67 // Asks the plug-in process to create a new connection to a web process. The connection identifier will be 
68 // encoded in the given argument encoder and sent back to the connection of the given web process.
69 void PluginProcessProxy::createWebProcessConnection(WebProcessProxy* webProcessProxy, CoreIPC::ArgumentEncoder* reply)
70 {
71     m_pendingConnectionReplies.append(make_pair(webProcessProxy, reply));
72
73     if (m_processLauncher->isLaunching()) {
74         m_numPendingConnectionRequests++;
75         return;
76     }
77
78     // Ask the plug-in process to create a connection. Since the plug-in can be waiting for a synchronous reply
79     // we need to make sure that this message is always processed, even when the plug-in is waiting for a synchronus reply.
80     m_connection->send(Messages::PluginProcess::CreateWebProcessConnection(), 0, CoreIPC::DispatchMessageEvenWhenWaitingForSyncReply);
81 }
82
83 void PluginProcessProxy::pluginProcessCrashedOrFailedToLaunch()
84 {
85     // The plug-in process must have crashed or exited, send any pending sync replies we might have.
86     while (!m_pendingConnectionReplies.isEmpty()) {
87         RefPtr<WebProcessProxy> replyWebProcessProxy = m_pendingConnectionReplies.first().first.release();
88         CoreIPC::ArgumentEncoder* reply = m_pendingConnectionReplies.first().second;
89         m_pendingConnectionReplies.removeFirst();
90
91         // FIXME: This is Mac specific.
92         reply->encode(CoreIPC::MachPort(0, MACH_MSG_TYPE_MOVE_SEND));
93         replyWebProcessProxy->connection()->sendSyncReply(reply);
94     }
95
96     // Tell the plug-in process manager to forget about this plug-in process proxy.
97     m_pluginProcessManager->removePluginProcessProxy(this);
98     delete this;
99 }
100
101 void PluginProcessProxy::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
102 {
103     didReceivePluginProcessProxyMessage(connection, messageID, arguments);
104 }
105
106 void PluginProcessProxy::didClose(CoreIPC::Connection*)
107 {
108     pluginProcessCrashedOrFailedToLaunch();
109 }
110
111 void PluginProcessProxy::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID)
112 {
113 }
114
115 void PluginProcessProxy::didFinishLaunching(ProcessLauncher*, CoreIPC::Connection::Identifier connectionIdentifier)
116 {
117     ASSERT(!m_connection);
118
119     if (!connectionIdentifier) {
120         pluginProcessCrashedOrFailedToLaunch();
121         return;
122     }
123     
124     m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main());
125     m_connection->open();
126     
127     PluginProcessCreationParameters parameters;
128
129     parameters.pluginPath = m_pluginInfo.path;
130
131     platformInitializePluginProcess(parameters);
132
133     // Initialize the plug-in host process.
134     m_connection->send(Messages::PluginProcess::InitializePluginProcess(parameters), 0);
135
136     // Send all our pending requests.
137     for (unsigned i = 0; i < m_numPendingConnectionRequests; ++i)
138         m_connection->send(Messages::PluginProcess::CreateWebProcessConnection(), 0);
139     
140     m_numPendingConnectionRequests = 0;
141 }
142
143 void PluginProcessProxy::didCreateWebProcessConnection(const CoreIPC::MachPort& machPort)
144 {
145     ASSERT(!m_pendingConnectionReplies.isEmpty());
146
147     // Grab the first pending connection reply.
148     RefPtr<WebProcessProxy> replyWebProcessProxy = m_pendingConnectionReplies.first().first.release();
149     CoreIPC::ArgumentEncoder* reply = m_pendingConnectionReplies.first().second;
150     m_pendingConnectionReplies.removeFirst();
151
152     // FIXME: This is Mac specific.
153     reply->encode(CoreIPC::MachPort(machPort.port(), MACH_MSG_TYPE_MOVE_SEND));
154     replyWebProcessProxy->connection()->sendSyncReply(reply);
155 }
156
157 } // namespace WebKit
158
159 #endif // ENABLE(PLUGIN_PROCESS)