Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Unified Diff: remoting/host/win/worker_process_launcher.cc

Issue 15077010: [Chromoting] Refactored worker process launching code and speeded up the desktop process launch. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 704ebcde39b5acc6fd1b662681661259460babac..47e0cf2efc06a8cc0a7a66538db8cec721c217d6 100644
--- a/remoting/host/win/worker_process_launcher.cc
+++ b/remoting/host/win/worker_process_launcher.cc
@@ -8,13 +8,10 @@
#include "base/logging.h"
#include "base/single_thread_task_runner.h"
#include "base/time.h"
-#include "base/timer.h"
-#include "base/win/object_watcher.h"
#include "base/win/windows_version.h"
-#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/host_exit_codes.h"
#include "remoting/host/worker_process_ipc_delegate.h"
using base::TimeDelta;
@@ -26,7 +23,7 @@ const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
0,
// Initial delay for exponential back-off in ms.
- 1000,
+ 100,
// Factor by which the waiting time will be multiplied.
2,
@@ -47,162 +44,38 @@ const net::BackoffEntry::Policy kDefaultBackoffPolicy = {
};
const int kKillProcessTimeoutSeconds = 5;
-const int kLaunchSuccessTimeoutSeconds = 2;
+const int kStartProcessTimeoutSeconds = 5;
namespace remoting {
-// Launches a worker process that is controlled via an IPC channel. All
-// interaction with the spawned process is through the IPC::Listener and Send()
-// method. In case of error the channel is closed and the worker process is
-// terminated.
-class WorkerProcessLauncher::Core
- : public base::RefCountedThreadSafe<Core, Core>,
- public base::win::ObjectWatcher::Delegate,
- public IPC::Listener {
- public:
- // Creates the launcher that will use |launcher_delegate| to manage the worker
- // process and |worker_delegate| to handle IPCs. The caller must ensure that
- // |worker_delegate| remains valid until Stoppable::Stop() method has been
- // called.
- //
- // The caller should call all the methods on this class on
- // the |caller_task_runner| thread. Methods of both delegate interfaces are
- // called on the |caller_task_runner| thread as well.
- Core(scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
- scoped_ptr<WorkerProcessLauncher::Delegate> launcher_delegate,
- WorkerProcessIpcDelegate* worker_delegate);
-
- // Launches the worker process.
- void Start();
-
- // Stops the worker process asynchronously. The caller can drop the reference
- // to |this| as soon as Stop() returns.
- void Stop();
-
- // 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;
-
- // IPC::Listener implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
- 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::DeleteHelper<Core>;
- virtual ~Core();
-
- // Attempts to launch the worker process. Schedules next launch attempt if
- // creation of the process fails.
- void LaunchWorker();
-
- // Records a successful launch attempt.
- void RecordSuccessfulLaunch();
-
- // Stops the worker process asynchronously and schedules next launch attempt
- // unless Stop() has been called already.
- void StopWorker();
-
- // All public methods are called on the |caller_task_runner| thread.
- scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
-
- // Implements specifics of launching a worker process.
- scoped_ptr<WorkerProcessLauncher::Delegate> launcher_delegate_;
-
- // Handles IPC messages sent by the worker process.
- WorkerProcessIpcDelegate* worker_delegate_;
-
- // Pointer to GetNamedPipeClientProcessId() API if it is available.
- typedef BOOL (WINAPI * GetNamedPipeClientProcessIdFn)(HANDLE, DWORD*);
- GetNamedPipeClientProcessIdFn get_named_pipe_client_pid_;
-
- // True if IPC messages should be passed to |worker_delegate_|.
- bool ipc_enabled_;
-
- // 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.
- base::OneShotTimer<Core> launch_success_timer_;
-
- // Timer used to schedule the next attempt to launch the process.
- base::OneShotTimer<Core> launch_timer_;
-
- // Used to determine when the launched process terminates.
- base::win::ObjectWatcher process_watcher_;
-
- // A waiting handle that becomes signalled once the launched process has
- // been terminated.
- ScopedHandle process_exit_event_;
-
- // True when Stop() has been called.
- bool stopping_;
-
- DISALLOW_COPY_AND_ASSIGN(Core);
-};
-
WorkerProcessLauncher::Delegate::~Delegate() {
}
-WorkerProcessLauncher::Core::Core(
- scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
+WorkerProcessLauncher::WorkerProcessLauncher(
scoped_ptr<WorkerProcessLauncher::Delegate> launcher_delegate,
WorkerProcessIpcDelegate* worker_delegate)
- : caller_task_runner_(caller_task_runner),
- launcher_delegate_(launcher_delegate.Pass()),
+ : launcher_delegate_(launcher_delegate.Pass()),
worker_delegate_(worker_delegate),
- get_named_pipe_client_pid_(NULL),
+ exit_code_(CONTROL_C_EXIT),
ipc_enabled_(false),
kill_process_timeout_(
base::TimeDelta::FromSeconds(kKillProcessTimeoutSeconds)),
launch_backoff_(&kDefaultBackoffPolicy),
stopping_(false) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
-}
-
-void WorkerProcessLauncher::Core::Start() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- DCHECK(!stopping_);
-
LaunchWorker();
}
-void WorkerProcessLauncher::Core::Stop() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
+WorkerProcessLauncher::~WorkerProcessLauncher() {
+ DCHECK(CalledOnValidThread());
- if (!stopping_) {
- stopping_ = true;
- worker_delegate_ = NULL;
- StopWorker();
- }
+ stopping_ = true;
+ worker_delegate_ = NULL;
Wez 2013/05/14 03:45:22 nit: You could turn stopping_ into a private stopp
alexeypa (please no reviews) 2013/05/14 18:31:10 Done.
+ StopWorker();
}
-void WorkerProcessLauncher::Core::Crash(
+void WorkerProcessLauncher::Crash(
const tracked_objects::Location& location) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
+ DCHECK(CalledOnValidThread());
// Ask the worker process to crash voluntarily if it is still connected.
if (ipc_enabled_) {
@@ -218,12 +91,12 @@ void WorkerProcessLauncher::Core::Crash(
// 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);
+ &WorkerProcessLauncher::StopWorker);
}
}
-void WorkerProcessLauncher::Core::Send(IPC::Message* message) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
+void WorkerProcessLauncher::Send(IPC::Message* message) {
+ DCHECK(CalledOnValidThread());
if (ipc_enabled_) {
launcher_delegate_->Send(message);
@@ -232,32 +105,32 @@ void WorkerProcessLauncher::Core::Send(IPC::Message* message) {
}
}
-void WorkerProcessLauncher::Core::ResetLaunchSuccessTimeoutForTest() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
+void WorkerProcessLauncher::OnProcessLaunched(
+ base::win::ScopedHandle worker_process) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!ipc_enabled_);
+ DCHECK(!launch_timer_.IsRunning());
+ DCHECK(!process_watcher_.GetWatchedObject());
+ DCHECK(!worker_process_.IsValid());
- if (launch_success_timer_.IsRunning()) {
- launch_success_timer_.Stop();
- RecordSuccessfulLaunch();
+ if (!process_watcher_.StartWatching(worker_process, this)) {
+ StopWorker();
+ return;
}
-}
-
-void WorkerProcessLauncher::Core::SetKillProcessTimeoutForTest(
- const base::TimeDelta& timeout) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- kill_process_timeout_ = timeout;
+ ipc_enabled_ = true;
+ worker_process_ = worker_process.Pass();
}
-void WorkerProcessLauncher::Core::OnObjectSignaled(HANDLE object) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- DCHECK(process_watcher_.GetWatchedObject() == NULL);
+void WorkerProcessLauncher::OnFatalError() {
+ DCHECK(CalledOnValidThread());
StopWorker();
}
-bool WorkerProcessLauncher::Core::OnMessageReceived(
- const IPC::Message& message) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
+bool WorkerProcessLauncher::OnMessageReceived(
+ const IPC::Message& message) {
+ DCHECK(CalledOnValidThread());
if (!ipc_enabled_)
return false;
@@ -265,30 +138,19 @@ bool WorkerProcessLauncher::Core::OnMessageReceived(
return worker_delegate_->OnMessageReceived(message);
}
-void WorkerProcessLauncher::Core::OnChannelConnected(int32 peer_pid) {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
+void WorkerProcessLauncher::OnChannelConnected(int32 peer_pid) {
+ DCHECK(CalledOnValidThread());
if (!ipc_enabled_)
return;
- // Verify |peer_pid| because it is controlled by the client and cannot be
- // trusted.
- DWORD actual_pid = launcher_delegate_->GetProcessId();
- if (peer_pid != static_cast<int32>(actual_pid)) {
- LOG(ERROR) << "The actual client PID " << actual_pid
- << " does not match the one reported by the client: "
- << peer_pid;
- StopWorker();
- return;
- }
-
// This can result in |this| being deleted, so this call must be the last in
// this method.
worker_delegate_->OnChannelConnected(peer_pid);
}
-void WorkerProcessLauncher::Core::OnChannelError() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
+void WorkerProcessLauncher::OnChannelError() {
+ DCHECK(CalledOnValidThread());
// Schedule a delayed termination of the worker process. Usually, the pipe is
// disconnected when the worker process is about to exit. Waiting a little bit
@@ -297,129 +159,111 @@ void WorkerProcessLauncher::Core::OnChannelError() {
// the original exit code reported by the worker process will be retrieved.
if (!kill_process_timer_.IsRunning()) {
kill_process_timer_.Start(FROM_HERE, kill_process_timeout_, this,
- &Core::StopWorker);
+ &WorkerProcessLauncher::StopWorker);
}
}
-// static
-void WorkerProcessLauncher::Core::Destruct(const Core* core) {
- core->caller_task_runner_->DeleteSoon(FROM_HERE, core);
-}
+void WorkerProcessLauncher::OnObjectSignaled(HANDLE object) {
Wez 2013/05/14 03:45:22 nit: Check that |object| is the |worker_process_|?
alexeypa (please no reviews) 2013/05/14 18:31:10 Done.
+ DCHECK(CalledOnValidThread());
+ DCHECK(!process_watcher_.GetWatchedObject());
+ DCHECK_EQ(exit_code_, CONTROL_C_EXIT);
-WorkerProcessLauncher::Core::~Core() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
- DCHECK(stopping_);
+ // Get exit code of the worker process if it is available.
+ if (!::GetExitCodeProcess(worker_process_, &exit_code_)) {
+ LOG_GETLASTERROR(INFO)
+ << "Failed to query the exit code of the worker process";
+ exit_code_ = CONTROL_C_EXIT;
+ }
+
+ worker_process_.Close();
+ StopWorker();
}
-void WorkerProcessLauncher::Core::LaunchWorker() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
+void WorkerProcessLauncher::LaunchWorker() {
+ DCHECK(CalledOnValidThread());
DCHECK(!ipc_enabled_);
- DCHECK(!launch_success_timer_.IsRunning());
+ DCHECK(!kill_process_timer_.IsRunning());
DCHECK(!launch_timer_.IsRunning());
- DCHECK(!process_exit_event_.IsValid());
- DCHECK(process_watcher_.GetWatchedObject() == NULL);
-
- // Launch the process and attach an object watcher to the returned process
- // handle so that we get notified if the process terminates.
- if (launcher_delegate_->LaunchProcess(this, &process_exit_event_)) {
- if (process_watcher_.StartWatching(process_exit_event_, this)) {
- 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(kLaunchSuccessTimeoutSeconds),
- this, &Core::RecordSuccessfulLaunch);
- return;
- }
-
- launcher_delegate_->KillProcess(CONTROL_C_EXIT);
- }
+ DCHECK(!process_watcher_.GetWatchedObject());
+ DCHECK(!start_process_timer_.IsRunning());
- launch_backoff_.InformOfRequest(false);
- StopWorker();
+ exit_code_ = CONTROL_C_EXIT;
+
+ // Make sure launching a process will not take forever.
+ start_process_timer_.Start(
+ FROM_HERE, base::TimeDelta::FromSeconds(kStartProcessTimeoutSeconds),
+ this, &WorkerProcessLauncher::RecordSuccessfulLaunch);
+
+ launcher_delegate_->LaunchProcess(this);
}
-void WorkerProcessLauncher::Core::RecordSuccessfulLaunch() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
+void WorkerProcessLauncher::RecordSuccessfulLaunch() {
Wez 2013/05/14 03:45:22 This method records both successful and unsuccessf
alexeypa (please no reviews) 2013/05/14 18:31:10 Done.
+ DCHECK(CalledOnValidThread());
+
+ if (!worker_process_.IsValid()) {
+ LOG(WARNING) << "A worker process didn't start in "
Wez 2013/05/14 03:45:22 nit: "... failed to start within ..."
alexeypa (please no reviews) 2013/05/14 18:31:10 Done.
+ << kStartProcessTimeoutSeconds << " seconds.";
+
+ launch_backoff_.InformOfRequest(false);
+ StopWorker();
+ return;
+ }
+ // Conside the launch attemp successful if the worker process has been running
+ // for a few seconds.
Wez 2013/05/14 03:45:22 nit: typos
alexeypa (please no reviews) 2013/05/14 18:31:10 Done.
launch_backoff_.InformOfRequest(true);
}
-void WorkerProcessLauncher::Core::StopWorker() {
- DCHECK(caller_task_runner_->BelongsToCurrentThread());
+void WorkerProcessLauncher::RecordSuccessfulLaunchForTest() {
+ DCHECK(CalledOnValidThread());
+
+ if (start_process_timer_.IsRunning()) {
+ start_process_timer_.Stop();
+ RecordSuccessfulLaunch();
+ }
+}
+
+void WorkerProcessLauncher::SetKillProcessTimeoutForTest(
+ const base::TimeDelta& timeout) {
+ DCHECK(CalledOnValidThread());
+
+ kill_process_timeout_ = timeout;
+}
- // Keep the object alive in case one of delegates decides to delete |this|.
- scoped_refptr<Core> self = this;
+void WorkerProcessLauncher::StopWorker() {
+ DCHECK(CalledOnValidThread());
// Record a launch failure if the process exited too soon.
- if (launch_success_timer_.IsRunning()) {
- launch_success_timer_.Stop();
+ if (start_process_timer_.IsRunning()) {
launch_backoff_.InformOfRequest(false);
+ start_process_timer_.Stop();
}
// Ignore any remaining IPC messages.
ipc_enabled_ = false;
- // Kill the process if it has been started already.
- if (process_watcher_.GetWatchedObject() != NULL) {
- launcher_delegate_->KillProcess(CONTROL_C_EXIT);
-
- // Wait until the process is actually stopped if the caller keeps
- // a reference to |this|. Otherwise terminate everything right now - there
- // won't be a second chance.
- if (!stopping_)
- return;
-
- process_watcher_.StopWatching();
- }
+ // Stop monitoring the worker process termination.
Wez 2013/05/14 03:45:22 nit: lose "termination".
alexeypa (please no reviews) 2013/05/14 18:31:10 Done.
+ process_watcher_.StopWatching();
+ worker_process_.Close();
kill_process_timer_.Stop();
- process_exit_event_.Close();
+ launcher_delegate_->KillProcess();
// Do not relaunch the worker process if the caller has asked us to stop.
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);
+ // Stop trying to restart the worker process if it exited due to
+ // misconfiguration.
+ if (kMinPermanentErrorExitCode <= exit_code_ &&
+ exit_code_ <= kMaxPermanentErrorExitCode) {
+ worker_delegate_->OnPermanentError();
+ return;
}
-}
-
-WorkerProcessLauncher::WorkerProcessLauncher(
- scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
- scoped_ptr<Delegate> launcher_delegate,
- WorkerProcessIpcDelegate* worker_delegate) {
- core_ = new Core(caller_task_runner, launcher_delegate.Pass(),
- worker_delegate);
- core_->Start();
-}
-
-WorkerProcessLauncher::~WorkerProcessLauncher() {
- core_->Stop();
- 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);
+ // Schedule the next attempt to launch the worker process.
+ launch_timer_.Start(FROM_HERE, launch_backoff_.GetTimeUntilRelease(), this,
+ &WorkerProcessLauncher::LaunchWorker);
}
-
} // namespace remoting

Powered by Google App Engine
This is Rietveld 408576698