ffa034a132fc5146ec798af174e0e5896429fb74
[WebKit-https.git] / Source / WebKit / UIProcess / AuxiliaryProcessProxy.cpp
1 /*
2  * Copyright (C) 2012-2018 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 "AuxiliaryProcessProxy.h"
28
29 #include "AuxiliaryProcessMessages.h"
30 #include <wtf/Environment.h>
31 #include <wtf/RunLoop.h>
32
33 namespace WebKit {
34
35 AuxiliaryProcessProxy::AuxiliaryProcessProxy(bool alwaysRunsAtBackgroundPriority)
36     : m_alwaysRunsAtBackgroundPriority(alwaysRunsAtBackgroundPriority)
37 {
38 }
39
40 AuxiliaryProcessProxy::~AuxiliaryProcessProxy()
41 {
42     if (m_connection)
43         m_connection->invalidate();
44
45     if (m_processLauncher) {
46         m_processLauncher->invalidate();
47         m_processLauncher = nullptr;
48     }
49 }
50
51 void AuxiliaryProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
52 {
53     launchOptions.processIdentifier = m_processIdentifier;
54
55     if (auto userDirectorySuffix = Environment::get("DIRHELPER_USER_DIR_SUFFIX"))
56         launchOptions.extraInitializationData.add("user-directory-suffix"_s, *userDirectorySuffix);
57
58     if (m_alwaysRunsAtBackgroundPriority)
59         launchOptions.extraInitializationData.add("always-runs-at-background-priority"_s, "true");
60
61 #if ENABLE(DEVELOPER_MODE) && (PLATFORM(GTK) || PLATFORM(WPE))
62     const char* varname;
63     switch (launchOptions.processType) {
64     case ProcessLauncher::ProcessType::Web:
65         varname = "WEB_PROCESS_CMD_PREFIX";
66         break;
67 #if ENABLE(NETSCAPE_PLUGIN_API)
68     case ProcessLauncher::ProcessType::Plugin64:
69     case ProcessLauncher::ProcessType::Plugin32:
70         varname = "PLUGIN_PROCESS_CMD_PREFIX";
71         break;
72 #endif
73     case ProcessLauncher::ProcessType::Network:
74         varname = "NETWORK_PROCESS_CMD_PREFIX";
75         break;
76     case ProcessLauncher::ProcessType::NetworkDaemon:
77         ASSERT_NOT_REACHED();
78         break;
79     }
80     auto processCmdPrefix = Environment::get(varname);
81     if (processCmdPrefix && !processCmdPrefix->isEmpty())
82         launchOptions.processCmdPrefix = *processCmdPrefix;
83 #endif // ENABLE(DEVELOPER_MODE) && (PLATFORM(GTK) || PLATFORM(WPE))
84
85     platformGetLaunchOptions(launchOptions);
86 }
87
88 void AuxiliaryProcessProxy::connect()
89 {
90     ASSERT(!m_processLauncher);
91     ProcessLauncher::LaunchOptions launchOptions;
92     getLaunchOptions(launchOptions);
93     m_processLauncher = ProcessLauncher::create(this, launchOptions);
94 }
95
96 void AuxiliaryProcessProxy::terminate()
97 {
98 #if PLATFORM(COCOA)
99     if (m_connection && m_connection->kill())
100         return;
101 #endif
102
103     // FIXME: We should really merge process launching into IPC connection creation and get rid of the process launcher.
104     if (m_processLauncher)
105         m_processLauncher->terminateProcess();
106 }
107
108 AuxiliaryProcessProxy::State AuxiliaryProcessProxy::state() const
109 {
110     if (m_processLauncher && m_processLauncher->isLaunching())
111         return AuxiliaryProcessProxy::State::Launching;
112
113     if (!m_connection)
114         return AuxiliaryProcessProxy::State::Terminated;
115
116     return AuxiliaryProcessProxy::State::Running;
117 }
118
119 bool AuxiliaryProcessProxy::sendMessage(std::unique_ptr<IPC::Encoder> encoder, OptionSet<IPC::SendOption> sendOptions)
120 {
121     switch (state()) {
122     case State::Launching:
123         // If we're waiting for the child process to launch, we need to stash away the messages so we can send them once we have a connection.
124         m_pendingMessages.append(std::make_pair(WTFMove(encoder), sendOptions));
125         return true;
126
127     case State::Running:
128         return connection()->sendMessage(WTFMove(encoder), sendOptions);
129
130     case State::Terminated:
131         return false;
132     }
133
134     return false;
135 }
136
137 void AuxiliaryProcessProxy::addMessageReceiver(IPC::StringReference messageReceiverName, IPC::MessageReceiver& messageReceiver)
138 {
139     m_messageReceiverMap.addMessageReceiver(messageReceiverName, messageReceiver);
140 }
141
142 void AuxiliaryProcessProxy::addMessageReceiver(IPC::StringReference messageReceiverName, uint64_t destinationID, IPC::MessageReceiver& messageReceiver)
143 {
144     m_messageReceiverMap.addMessageReceiver(messageReceiverName, destinationID, messageReceiver);
145 }
146
147 void AuxiliaryProcessProxy::removeMessageReceiver(IPC::StringReference messageReceiverName, uint64_t destinationID)
148 {
149     m_messageReceiverMap.removeMessageReceiver(messageReceiverName, destinationID);
150 }
151
152 void AuxiliaryProcessProxy::removeMessageReceiver(IPC::StringReference messageReceiverName)
153 {
154     m_messageReceiverMap.removeMessageReceiver(messageReceiverName);
155 }
156
157 bool AuxiliaryProcessProxy::dispatchMessage(IPC::Connection& connection, IPC::Decoder& decoder)
158 {
159     return m_messageReceiverMap.dispatchMessage(connection, decoder);
160 }
161
162 bool AuxiliaryProcessProxy::dispatchSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& replyEncoder)
163 {
164     return m_messageReceiverMap.dispatchSyncMessage(connection, decoder, replyEncoder);
165 }
166
167 void AuxiliaryProcessProxy::didFinishLaunching(ProcessLauncher*, IPC::Connection::Identifier connectionIdentifier)
168 {
169     ASSERT(!m_connection);
170
171     if (!IPC::Connection::identifierIsValid(connectionIdentifier))
172         return;
173
174     m_connection = IPC::Connection::createServerConnection(connectionIdentifier, *this);
175
176     connectionWillOpen(*m_connection);
177     m_connection->open();
178
179     for (size_t i = 0; i < m_pendingMessages.size(); ++i) {
180         std::unique_ptr<IPC::Encoder> message = WTFMove(m_pendingMessages[i].first);
181         OptionSet<IPC::SendOption> sendOptions = m_pendingMessages[i].second;
182         m_connection->sendMessage(WTFMove(message), sendOptions);
183     }
184
185     m_pendingMessages.clear();
186 }
187
188 void AuxiliaryProcessProxy::shutDownProcess()
189 {
190     switch (state()) {
191     case State::Launching:
192         m_processLauncher->invalidate();
193         m_processLauncher = nullptr;
194         break;
195     case State::Running:
196 #if PLATFORM(IOS_FAMILY)
197         // On iOS deploy a watchdog in the UI process, since the child process may be suspended.
198         // If 30s is insufficient for any outstanding activity to complete cleanly, then it will be killed.
199         ASSERT(m_connection);
200         m_connection->terminateSoon(30_s);
201 #endif
202         break;
203     case State::Terminated:
204         return;
205     }
206
207     if (!m_connection)
208         return;
209
210     processWillShutDown(*m_connection);
211
212     if (canSendMessage())
213         send(Messages::AuxiliaryProcess::ShutDown(), 0);
214
215     m_connection->invalidate();
216     m_connection = nullptr;
217 }
218
219 void AuxiliaryProcessProxy::setProcessSuppressionEnabled(bool processSuppressionEnabled)
220 {
221 #if PLATFORM(COCOA)
222     if (state() != State::Running)
223         return;
224
225     connection()->send(Messages::AuxiliaryProcess::SetProcessSuppressionEnabled(processSuppressionEnabled), 0);
226 #else
227     UNUSED_PARAM(processSuppressionEnabled);
228 #endif
229 }
230
231 void AuxiliaryProcessProxy::connectionWillOpen(IPC::Connection&)
232 {
233 }
234
235 } // namespace WebKit