| 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 |