OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/host/win/worker_process_launcher.h" | 5 #include "remoting/host/win/worker_process_launcher.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/location.h" | 9 #include "base/location.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 ipc_enabled_(false), | 60 ipc_enabled_(false), |
61 kill_process_timeout_( | 61 kill_process_timeout_( |
62 base::TimeDelta::FromSeconds(kKillProcessTimeoutSeconds)), | 62 base::TimeDelta::FromSeconds(kKillProcessTimeoutSeconds)), |
63 launch_backoff_(&kDefaultBackoffPolicy) { | 63 launch_backoff_(&kDefaultBackoffPolicy) { |
64 DCHECK(ipc_handler_ != nullptr); | 64 DCHECK(ipc_handler_ != nullptr); |
65 | 65 |
66 LaunchWorker(); | 66 LaunchWorker(); |
67 } | 67 } |
68 | 68 |
69 WorkerProcessLauncher::~WorkerProcessLauncher() { | 69 WorkerProcessLauncher::~WorkerProcessLauncher() { |
70 DCHECK(CalledOnValidThread()); | 70 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
71 | 71 |
72 ipc_handler_ = nullptr; | 72 ipc_handler_ = nullptr; |
73 StopWorker(); | 73 StopWorker(); |
74 } | 74 } |
75 | 75 |
76 void WorkerProcessLauncher::Crash( | 76 void WorkerProcessLauncher::Crash( |
77 const tracked_objects::Location& location) { | 77 const tracked_objects::Location& location) { |
78 DCHECK(CalledOnValidThread()); | 78 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
79 | 79 |
80 // Ask the worker process to crash voluntarily if it is still connected. | 80 // Ask the worker process to crash voluntarily if it is still connected. |
81 if (ipc_enabled_) { | 81 if (ipc_enabled_) { |
82 Send(new ChromotingDaemonMsg_Crash(location.function_name(), | 82 Send(new ChromotingDaemonMsg_Crash(location.function_name(), |
83 location.file_name(), | 83 location.file_name(), |
84 location.line_number())); | 84 location.line_number())); |
85 } | 85 } |
86 | 86 |
87 // Close the channel and ignore any not yet processed messages. | 87 // Close the channel and ignore any not yet processed messages. |
88 launcher_delegate_->CloseChannel(); | 88 launcher_delegate_->CloseChannel(); |
89 ipc_enabled_ = false; | 89 ipc_enabled_ = false; |
90 | 90 |
91 // Give the worker process some time to crash. | 91 // Give the worker process some time to crash. |
92 if (!kill_process_timer_.IsRunning()) { | 92 if (!kill_process_timer_.IsRunning()) { |
93 kill_process_timer_.Start(FROM_HERE, kill_process_timeout_, this, | 93 kill_process_timer_.Start(FROM_HERE, kill_process_timeout_, this, |
94 &WorkerProcessLauncher::StopWorker); | 94 &WorkerProcessLauncher::StopWorker); |
95 } | 95 } |
96 } | 96 } |
97 | 97 |
98 void WorkerProcessLauncher::Send(IPC::Message* message) { | 98 void WorkerProcessLauncher::Send(IPC::Message* message) { |
99 DCHECK(CalledOnValidThread()); | 99 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
100 | 100 |
101 if (ipc_enabled_) { | 101 if (ipc_enabled_) { |
102 launcher_delegate_->Send(message); | 102 launcher_delegate_->Send(message); |
103 } else { | 103 } else { |
104 delete message; | 104 delete message; |
105 } | 105 } |
106 } | 106 } |
107 | 107 |
108 void WorkerProcessLauncher::OnProcessLaunched( | 108 void WorkerProcessLauncher::OnProcessLaunched( |
109 base::win::ScopedHandle worker_process) { | 109 base::win::ScopedHandle worker_process) { |
110 DCHECK(CalledOnValidThread()); | 110 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
111 DCHECK(!ipc_enabled_); | 111 DCHECK(!ipc_enabled_); |
112 DCHECK(!launch_timer_.IsRunning()); | 112 DCHECK(!launch_timer_.IsRunning()); |
113 DCHECK(!process_watcher_.GetWatchedObject()); | 113 DCHECK(!process_watcher_.GetWatchedObject()); |
114 DCHECK(!worker_process_.IsValid()); | 114 DCHECK(!worker_process_.IsValid()); |
115 | 115 |
116 if (!process_watcher_.StartWatchingOnce(worker_process.Get(), this)) { | 116 if (!process_watcher_.StartWatchingOnce(worker_process.Get(), this)) { |
117 StopWorker(); | 117 StopWorker(); |
118 return; | 118 return; |
119 } | 119 } |
120 | 120 |
121 ipc_enabled_ = true; | 121 ipc_enabled_ = true; |
122 worker_process_ = std::move(worker_process); | 122 worker_process_ = std::move(worker_process); |
123 } | 123 } |
124 | 124 |
125 void WorkerProcessLauncher::OnFatalError() { | 125 void WorkerProcessLauncher::OnFatalError() { |
126 DCHECK(CalledOnValidThread()); | 126 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
127 | 127 |
128 StopWorker(); | 128 StopWorker(); |
129 } | 129 } |
130 | 130 |
131 bool WorkerProcessLauncher::OnMessageReceived( | 131 bool WorkerProcessLauncher::OnMessageReceived( |
132 const IPC::Message& message) { | 132 const IPC::Message& message) { |
133 DCHECK(CalledOnValidThread()); | 133 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
134 | 134 |
135 if (!ipc_enabled_) | 135 if (!ipc_enabled_) |
136 return false; | 136 return false; |
137 | 137 |
138 return ipc_handler_->OnMessageReceived(message); | 138 return ipc_handler_->OnMessageReceived(message); |
139 } | 139 } |
140 | 140 |
141 void WorkerProcessLauncher::OnChannelConnected(int32_t peer_pid) { | 141 void WorkerProcessLauncher::OnChannelConnected(int32_t peer_pid) { |
142 DCHECK(CalledOnValidThread()); | 142 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
143 | 143 |
144 if (!ipc_enabled_) | 144 if (!ipc_enabled_) |
145 return; | 145 return; |
146 | 146 |
147 // This can result in |this| being deleted, so this call must be the last in | 147 // This can result in |this| being deleted, so this call must be the last in |
148 // this method. | 148 // this method. |
149 ipc_handler_->OnChannelConnected(peer_pid); | 149 ipc_handler_->OnChannelConnected(peer_pid); |
150 } | 150 } |
151 | 151 |
152 void WorkerProcessLauncher::OnChannelError() { | 152 void WorkerProcessLauncher::OnChannelError() { |
153 DCHECK(CalledOnValidThread()); | 153 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
154 | 154 |
155 // Schedule a delayed termination of the worker process. Usually, the pipe is | 155 // Schedule a delayed termination of the worker process. Usually, the pipe is |
156 // disconnected when the worker process is about to exit. Waiting a little bit | 156 // disconnected when the worker process is about to exit. Waiting a little bit |
157 // here allows the worker to exit completely and so, notify | 157 // here allows the worker to exit completely and so, notify |
158 // |process_watcher_|. As the result KillProcess() will not be called and | 158 // |process_watcher_|. As the result KillProcess() will not be called and |
159 // the original exit code reported by the worker process will be retrieved. | 159 // the original exit code reported by the worker process will be retrieved. |
160 if (!kill_process_timer_.IsRunning()) { | 160 if (!kill_process_timer_.IsRunning()) { |
161 kill_process_timer_.Start(FROM_HERE, kill_process_timeout_, this, | 161 kill_process_timer_.Start(FROM_HERE, kill_process_timeout_, this, |
162 &WorkerProcessLauncher::StopWorker); | 162 &WorkerProcessLauncher::StopWorker); |
163 } | 163 } |
164 } | 164 } |
165 | 165 |
166 void WorkerProcessLauncher::OnObjectSignaled(HANDLE object) { | 166 void WorkerProcessLauncher::OnObjectSignaled(HANDLE object) { |
167 DCHECK(CalledOnValidThread()); | 167 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
168 DCHECK(!process_watcher_.GetWatchedObject()); | 168 DCHECK(!process_watcher_.GetWatchedObject()); |
169 DCHECK_EQ(exit_code_, CONTROL_C_EXIT); | 169 DCHECK_EQ(exit_code_, CONTROL_C_EXIT); |
170 DCHECK_EQ(worker_process_.Get(), object); | 170 DCHECK_EQ(worker_process_.Get(), object); |
171 | 171 |
172 // Get exit code of the worker process if it is available. | 172 // Get exit code of the worker process if it is available. |
173 if (!::GetExitCodeProcess(worker_process_.Get(), &exit_code_)) { | 173 if (!::GetExitCodeProcess(worker_process_.Get(), &exit_code_)) { |
174 PLOG(INFO) << "Failed to query the exit code of the worker process"; | 174 PLOG(INFO) << "Failed to query the exit code of the worker process"; |
175 exit_code_ = CONTROL_C_EXIT; | 175 exit_code_ = CONTROL_C_EXIT; |
176 } | 176 } |
177 | 177 |
178 worker_process_.Close(); | 178 worker_process_.Close(); |
179 StopWorker(); | 179 StopWorker(); |
180 } | 180 } |
181 | 181 |
182 void WorkerProcessLauncher::LaunchWorker() { | 182 void WorkerProcessLauncher::LaunchWorker() { |
183 DCHECK(CalledOnValidThread()); | 183 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
184 DCHECK(!ipc_enabled_); | 184 DCHECK(!ipc_enabled_); |
185 DCHECK(!kill_process_timer_.IsRunning()); | 185 DCHECK(!kill_process_timer_.IsRunning()); |
186 DCHECK(!launch_timer_.IsRunning()); | 186 DCHECK(!launch_timer_.IsRunning()); |
187 DCHECK(!process_watcher_.GetWatchedObject()); | 187 DCHECK(!process_watcher_.GetWatchedObject()); |
188 DCHECK(!launch_result_timer_.IsRunning()); | 188 DCHECK(!launch_result_timer_.IsRunning()); |
189 | 189 |
190 exit_code_ = CONTROL_C_EXIT; | 190 exit_code_ = CONTROL_C_EXIT; |
191 | 191 |
192 // Make sure launching a process will not take forever. | 192 // Make sure launching a process will not take forever. |
193 launch_result_timer_.Start( | 193 launch_result_timer_.Start( |
194 FROM_HERE, base::TimeDelta::FromSeconds(kLaunchResultTimeoutSeconds), | 194 FROM_HERE, base::TimeDelta::FromSeconds(kLaunchResultTimeoutSeconds), |
195 this, &WorkerProcessLauncher::RecordLaunchResult); | 195 this, &WorkerProcessLauncher::RecordLaunchResult); |
196 | 196 |
197 launcher_delegate_->LaunchProcess(this); | 197 launcher_delegate_->LaunchProcess(this); |
198 } | 198 } |
199 | 199 |
200 void WorkerProcessLauncher::RecordLaunchResult() { | 200 void WorkerProcessLauncher::RecordLaunchResult() { |
201 DCHECK(CalledOnValidThread()); | 201 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
202 | 202 |
203 if (!worker_process_.IsValid()) { | 203 if (!worker_process_.IsValid()) { |
204 LOG(WARNING) << "A worker process failed to start within " | 204 LOG(WARNING) << "A worker process failed to start within " |
205 << kLaunchResultTimeoutSeconds << " seconds."; | 205 << kLaunchResultTimeoutSeconds << " seconds."; |
206 | 206 |
207 launch_backoff_.InformOfRequest(false); | 207 launch_backoff_.InformOfRequest(false); |
208 StopWorker(); | 208 StopWorker(); |
209 return; | 209 return; |
210 } | 210 } |
211 | 211 |
212 // Assume success if the worker process has been running for a few seconds. | 212 // Assume success if the worker process has been running for a few seconds. |
213 launch_backoff_.InformOfRequest(true); | 213 launch_backoff_.InformOfRequest(true); |
214 } | 214 } |
215 | 215 |
216 void WorkerProcessLauncher::RecordSuccessfulLaunchForTest() { | 216 void WorkerProcessLauncher::RecordSuccessfulLaunchForTest() { |
217 DCHECK(CalledOnValidThread()); | 217 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
218 | 218 |
219 if (launch_result_timer_.IsRunning()) { | 219 if (launch_result_timer_.IsRunning()) { |
220 launch_result_timer_.Stop(); | 220 launch_result_timer_.Stop(); |
221 RecordLaunchResult(); | 221 RecordLaunchResult(); |
222 } | 222 } |
223 } | 223 } |
224 | 224 |
225 void WorkerProcessLauncher::SetKillProcessTimeoutForTest( | 225 void WorkerProcessLauncher::SetKillProcessTimeoutForTest( |
226 const base::TimeDelta& timeout) { | 226 const base::TimeDelta& timeout) { |
227 DCHECK(CalledOnValidThread()); | 227 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
228 | 228 |
229 kill_process_timeout_ = timeout; | 229 kill_process_timeout_ = timeout; |
230 } | 230 } |
231 | 231 |
232 void WorkerProcessLauncher::StopWorker() { | 232 void WorkerProcessLauncher::StopWorker() { |
233 DCHECK(CalledOnValidThread()); | 233 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
234 | 234 |
235 // Record a launch failure if the process exited too soon. | 235 // Record a launch failure if the process exited too soon. |
236 if (launch_result_timer_.IsRunning()) { | 236 if (launch_result_timer_.IsRunning()) { |
237 launch_backoff_.InformOfRequest(false); | 237 launch_backoff_.InformOfRequest(false); |
238 launch_result_timer_.Stop(); | 238 launch_result_timer_.Stop(); |
239 } | 239 } |
240 | 240 |
241 // Ignore any remaining IPC messages. | 241 // Ignore any remaining IPC messages. |
242 ipc_enabled_ = false; | 242 ipc_enabled_ = false; |
243 | 243 |
(...skipping 15 matching lines...) Expand all Loading... |
259 ipc_handler_->OnPermanentError(exit_code_); | 259 ipc_handler_->OnPermanentError(exit_code_); |
260 return; | 260 return; |
261 } | 261 } |
262 | 262 |
263 // Schedule the next attempt to launch the worker process. | 263 // Schedule the next attempt to launch the worker process. |
264 launch_timer_.Start(FROM_HERE, launch_backoff_.GetTimeUntilRelease(), this, | 264 launch_timer_.Start(FROM_HERE, launch_backoff_.GetTimeUntilRelease(), this, |
265 &WorkerProcessLauncher::LaunchWorker); | 265 &WorkerProcessLauncher::LaunchWorker); |
266 } | 266 } |
267 | 267 |
268 } // namespace remoting | 268 } // namespace remoting |
OLD | NEW |