Index: remoting/host/win/worker_process_launcher.cc |
diff --git a/remoting/host/win/worker_process_launcher.cc b/remoting/host/win/worker_process_launcher.cc |
index 6ca563cf8939e86084b4f42474b1eae250510f3b..704ebcde39b5acc6fd1b662681661259460babac 100644 |
--- a/remoting/host/win/worker_process_launcher.cc |
+++ b/remoting/host/win/worker_process_launcher.cc |
@@ -4,6 +4,7 @@ |
#include "remoting/host/win/worker_process_launcher.h" |
+#include "base/location.h" |
#include "base/logging.h" |
#include "base/single_thread_task_runner.h" |
#include "base/time.h" |
@@ -13,6 +14,7 @@ |
#include "ipc/ipc_listener.h" |
#include "ipc/ipc_message.h" |
#include "net/base/backoff_entry.h" |
+#include "remoting/host/chromoting_messages.h" |
#include "remoting/host/worker_process_ipc_delegate.h" |
using base::TimeDelta; |
@@ -44,6 +46,8 @@ const net::BackoffEntry::Policy kDefaultBackoffPolicy = { |
false, |
}; |
+const int kKillProcessTimeoutSeconds = 5; |
+const int kLaunchSuccessTimeoutSeconds = 2; |
namespace remoting { |
@@ -52,7 +56,7 @@ namespace remoting { |
// method. In case of error the channel is closed and the worker process is |
// terminated. |
class WorkerProcessLauncher::Core |
- : public base::RefCountedThreadSafe<WorkerProcessLauncher::Core>, |
+ : public base::RefCountedThreadSafe<Core, Core>, |
public base::win::ObjectWatcher::Delegate, |
public IPC::Listener { |
public: |
@@ -75,11 +79,18 @@ class WorkerProcessLauncher::Core |
// to |this| as soon as Stop() returns. |
void Stop(); |
- // Sends an IPC message to the worker process. The message will be silently |
- // dropped if Send() is called before Start() or after stutdown has been |
- // initiated. |
+ // See WorkerProcessLauncher::Crash(). |
+ void Crash(const tracked_objects::Location& location); |
+ |
+ // See WorkerProcessLauncher::Send(). |
void Send(IPC::Message* message); |
+ // Used to emulate |launch_success_timer_| expiration. |
+ void ResetLaunchSuccessTimeoutForTest(); |
+ |
+ // Set the desired timeout for |kill_process_timer_|. |
+ void SetKillProcessTimeoutForTest(const base::TimeDelta& timeout); |
+ |
// base::win::ObjectWatcher::Delegate implementation. |
virtual void OnObjectSignaled(HANDLE object) OVERRIDE; |
@@ -88,8 +99,13 @@ class WorkerProcessLauncher::Core |
virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; |
virtual void OnChannelError() OVERRIDE; |
+ // Destroys |Core| instances on the |caller_task_runner_| thread. This is |
+ // needed because base::OneShotTimer instances must be destroyed on the same |
+ // thread they were created on. |
+ static void Destruct(const Core* core); |
+ |
private: |
- friend class base::RefCountedThreadSafe<Core>; |
+ friend class base::DeleteHelper<Core>; |
virtual ~Core(); |
// Attempts to launch the worker process. Schedules next launch attempt if |
@@ -119,18 +135,21 @@ class WorkerProcessLauncher::Core |
// True if IPC messages should be passed to |worker_delegate_|. |
bool ipc_enabled_; |
- // The timer used to delay termination of the process in the case of an IPC |
- // error. |
- scoped_ptr<base::OneShotTimer<Core> > ipc_error_timer_; |
+ // The timer used to delay termination of the worker process when an IPC error |
+ // occured or when Crash() request is pending |
+ base::OneShotTimer<Core> kill_process_timer_; |
+ |
+ // The default timeout for |kill_process_timer_|. |
+ base::TimeDelta kill_process_timeout_; |
// Launch backoff state. |
net::BackoffEntry launch_backoff_; |
// Timer used to delay recording a successfull launch. |
- scoped_ptr<base::OneShotTimer<Core> > launch_success_timer_; |
+ base::OneShotTimer<Core> launch_success_timer_; |
// Timer used to schedule the next attempt to launch the process. |
- scoped_ptr<base::OneShotTimer<Core> > launch_timer_; |
+ base::OneShotTimer<Core> launch_timer_; |
// Used to determine when the launched process terminates. |
base::win::ObjectWatcher process_watcher_; |
@@ -157,14 +176,11 @@ WorkerProcessLauncher::Core::Core( |
worker_delegate_(worker_delegate), |
get_named_pipe_client_pid_(NULL), |
ipc_enabled_(false), |
+ kill_process_timeout_( |
+ base::TimeDelta::FromSeconds(kKillProcessTimeoutSeconds)), |
launch_backoff_(&kDefaultBackoffPolicy), |
stopping_(false) { |
DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
- |
- // base::OneShotTimer must be destroyed on the same thread it was created on. |
- ipc_error_timer_.reset(new base::OneShotTimer<Core>()); |
- launch_success_timer_.reset(new base::OneShotTimer<Core>()); |
- launch_timer_.reset(new base::OneShotTimer<Core>()); |
} |
void WorkerProcessLauncher::Core::Start() { |
@@ -184,6 +200,28 @@ void WorkerProcessLauncher::Core::Stop() { |
} |
} |
+void WorkerProcessLauncher::Core::Crash( |
+ const tracked_objects::Location& location) { |
+ DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
+ |
+ // Ask the worker process to crash voluntarily if it is still connected. |
+ if (ipc_enabled_) { |
+ Send(new ChromotingDaemonMsg_Crash(location.function_name(), |
+ location.file_name(), |
+ location.line_number())); |
+ } |
+ |
+ // Close the channel and ignore any not yet processed messages. |
+ launcher_delegate_->CloseChannel(); |
+ ipc_enabled_ = false; |
+ |
+ // Give the worker process some time to crash. |
+ if (!kill_process_timer_.IsRunning()) { |
+ kill_process_timer_.Start(FROM_HERE, kill_process_timeout_, this, |
+ &Core::StopWorker); |
+ } |
+} |
+ |
void WorkerProcessLauncher::Core::Send(IPC::Message* message) { |
DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
@@ -194,6 +232,22 @@ void WorkerProcessLauncher::Core::Send(IPC::Message* message) { |
} |
} |
+void WorkerProcessLauncher::Core::ResetLaunchSuccessTimeoutForTest() { |
+ DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
+ |
+ if (launch_success_timer_.IsRunning()) { |
+ launch_success_timer_.Stop(); |
+ RecordSuccessfulLaunch(); |
+ } |
+} |
+ |
+void WorkerProcessLauncher::Core::SetKillProcessTimeoutForTest( |
+ const base::TimeDelta& timeout) { |
+ DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
+ |
+ kill_process_timeout_ = timeout; |
+} |
+ |
void WorkerProcessLauncher::Core::OnObjectSignaled(HANDLE object) { |
DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
DCHECK(process_watcher_.GetWatchedObject() == NULL); |
@@ -241,19 +295,27 @@ void WorkerProcessLauncher::Core::OnChannelError() { |
// here allows the worker to exit completely and so, notify |
// |process_watcher_|. As the result KillProcess() will not be called and |
// the original exit code reported by the worker process will be retrieved. |
- ipc_error_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(5), |
- this, &Core::StopWorker); |
+ if (!kill_process_timer_.IsRunning()) { |
+ kill_process_timer_.Start(FROM_HERE, kill_process_timeout_, this, |
+ &Core::StopWorker); |
+ } |
+} |
+ |
+// static |
+void WorkerProcessLauncher::Core::Destruct(const Core* core) { |
+ core->caller_task_runner_->DeleteSoon(FROM_HERE, core); |
} |
WorkerProcessLauncher::Core::~Core() { |
+ DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
DCHECK(stopping_); |
} |
void WorkerProcessLauncher::Core::LaunchWorker() { |
DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
DCHECK(!ipc_enabled_); |
- DCHECK(!launch_success_timer_->IsRunning()); |
- DCHECK(!launch_timer_->IsRunning()); |
+ DCHECK(!launch_success_timer_.IsRunning()); |
+ DCHECK(!launch_timer_.IsRunning()); |
DCHECK(!process_exit_event_.IsValid()); |
DCHECK(process_watcher_.GetWatchedObject() == NULL); |
@@ -264,8 +326,9 @@ void WorkerProcessLauncher::Core::LaunchWorker() { |
ipc_enabled_ = true; |
// Record a successful launch once the process has been running for at |
// least two seconds. |
- launch_success_timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(2), |
- this, &Core::RecordSuccessfulLaunch); |
+ launch_success_timer_.Start( |
+ FROM_HERE, base::TimeDelta::FromSeconds(kLaunchSuccessTimeoutSeconds), |
+ this, &Core::RecordSuccessfulLaunch); |
return; |
} |
@@ -289,8 +352,8 @@ void WorkerProcessLauncher::Core::StopWorker() { |
scoped_refptr<Core> self = this; |
// Record a launch failure if the process exited too soon. |
- if (launch_success_timer_->IsRunning()) { |
- launch_success_timer_->Stop(); |
+ if (launch_success_timer_.IsRunning()) { |
+ launch_success_timer_.Stop(); |
launch_backoff_.InformOfRequest(false); |
} |
@@ -310,23 +373,20 @@ void WorkerProcessLauncher::Core::StopWorker() { |
process_watcher_.StopWatching(); |
} |
- ipc_error_timer_->Stop(); |
+ kill_process_timer_.Stop(); |
process_exit_event_.Close(); |
// Do not relaunch the worker process if the caller has asked us to stop. |
- if (stopping_) { |
- ipc_error_timer_.reset(); |
- launch_timer_.reset(); |
+ if (stopping_) |
return; |
- } |
if (launcher_delegate_->IsPermanentError(launch_backoff_.failure_count())) { |
if (!stopping_) |
worker_delegate_->OnPermanentError(); |
} else { |
// Schedule the next attempt to launch the worker process. |
- launch_timer_->Start(FROM_HERE, launch_backoff_.GetTimeUntilRelease(), |
- this, &Core::LaunchWorker); |
+ launch_timer_.Start(FROM_HERE, launch_backoff_.GetTimeUntilRelease(), this, |
+ &Core::LaunchWorker); |
} |
} |
@@ -344,8 +404,22 @@ WorkerProcessLauncher::~WorkerProcessLauncher() { |
core_ = NULL; |
} |
+void WorkerProcessLauncher::Crash(const tracked_objects::Location& location) { |
+ core_->Crash(location); |
+} |
+ |
void WorkerProcessLauncher::Send(IPC::Message* message) { |
core_->Send(message); |
} |
+void WorkerProcessLauncher::ResetLaunchSuccessTimeoutForTest() { |
+ core_->ResetLaunchSuccessTimeoutForTest(); |
+} |
+ |
+void WorkerProcessLauncher::SetKillProcessTimeoutForTest( |
+ const base::TimeDelta& timeout) { |
+ core_->SetKillProcessTimeoutForTest(timeout); |
+} |
+ |
+ |
} // namespace remoting |