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