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