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

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

Issue 10911267: [Chromoting] Don't use a job object to control the me2me host process on Windows XP. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: made compilable on VS2008. Created 8 years, 3 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
« no previous file with comments | « remoting/host/win/wts_session_process_launcher.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: remoting/host/win/wts_session_process_launcher.cc
diff --git a/remoting/host/win/wts_session_process_launcher.cc b/remoting/host/win/wts_session_process_launcher.cc
index d659f156be51f2a91e7d86242f0edb463f28fa41..969609813f27a4c5a8949416ef2300aebb55457d 100644
--- a/remoting/host/win/wts_session_process_launcher.cc
+++ b/remoting/host/win/wts_session_process_launcher.cc
@@ -24,6 +24,7 @@
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
#include "ipc/ipc_channel_proxy.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
@@ -66,80 +67,275 @@ const char kDaemonIpcSecurityDescriptor[] = "O:SYG:SYD:(A;;GA;;;SY)";
namespace remoting {
-WtsSessionProcessLauncher::WtsSessionProcessLauncher(
- const base::Closure& stopped_callback,
- WtsConsoleMonitor* monitor,
- scoped_refptr<base::SingleThreadTaskRunner> main_message_loop,
- scoped_refptr<base::SingleThreadTaskRunner> ipc_message_loop)
- : Stoppable(main_message_loop, stopped_callback),
- attached_(false),
- main_message_loop_(main_message_loop),
- ipc_message_loop_(ipc_message_loop),
- monitor_(monitor),
- job_state_(kJobUninitialized) {
- monitor_->AddWtsConsoleObserver(this);
+class WtsSessionProcessLauncherImpl
+ : public base::RefCountedThreadSafe<WtsSessionProcessLauncherImpl>,
+ public WorkerProcessLauncher::Delegate {
+ public:
+ // Returns the exit code of the worker process.
+ virtual DWORD GetExitCode() = 0;
- process_exit_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
- CHECK(process_exit_event_.IsValid());
+ // Sets the token to be used to launch the worker process.
+ virtual void ResetUserToken(ScopedHandle* user_token) = 0;
+
+ // Stops the object asynchronously.
+ virtual void Stop() = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<WtsSessionProcessLauncherImpl>;
+ virtual ~WtsSessionProcessLauncherImpl();
+};
+
+namespace {
- // To receive job object notifications it is registered with the completion
- // port represented by |ipc_message_loop|. The registration has to be done on
- // the I/O thread because MessageLoopForIO::RegisterJobObject() can only be
- // called via MessageLoopForIO::current().
- ipc_message_loop_->PostTask(FROM_HERE, base::Bind(
- &WtsSessionProcessLauncher::InitializeJob,
- base::Unretained(this)));
+// Implements |WorkerProcessLauncher::Delegate| that starts the specified
+// process in a different session via CreateProcessAsUser() and uses
+// the returned handle to monitor and terminate the process.
+class SingleProcessLauncher : public WtsSessionProcessLauncherImpl {
+ public:
+ SingleProcessLauncher(
+ const FilePath& binary_path,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+
+ // WorkerProcessLauncher::Delegate implementation.
+ virtual bool DoLaunchProcess(
+ const std::string& channel_name,
+ ScopedHandle* process_exit_event_out) OVERRIDE;
+ virtual void DoKillProcess(DWORD exit_code) OVERRIDE;
+
+ // WtsSessionProcessLauncherImpl implementation.
+ virtual DWORD GetExitCode() OVERRIDE;
+ virtual void ResetUserToken(ScopedHandle* user_token) OVERRIDE;
+ virtual void Stop() OVERRIDE;
+
+ private:
+ FilePath binary_path_;
+
+ // The task runner all public methods of this class should be called on.
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+
+ // A handle that becomes signalled once the process associated has been
+ // terminated.
+ ScopedHandle process_exit_event_;
+
+ // The token to be used to launch a process in a different session.
+ ScopedHandle user_token_;
+
+ // The handle of the worker process, if launched.
+ ScopedHandle worker_process_;
+
+ DISALLOW_COPY_AND_ASSIGN(SingleProcessLauncher);
+};
+
+// Implements |WorkerProcessLauncher::Delegate| that starts the specified
+// process (UAC) elevated in a different session. |ElevatedProcessLauncher|
+// utilizes a helper process to bypass limitations of ShellExecute() which
+// cannot spawn processes across the session boundary.
+class ElevatedProcessLauncher : public WtsSessionProcessLauncherImpl,
+ public base::MessagePumpForIO::IOHandler {
+ public:
+ ElevatedProcessLauncher(
+ const FilePath& binary_path,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
+
+ // base::MessagePumpForIO::IOHandler implementation.
+ virtual void OnIOCompleted(base::MessagePumpForIO::IOContext* context,
+ DWORD bytes_transferred,
+ DWORD error) OVERRIDE;
+
+ // WorkerProcessLauncher::Delegate implementation.
+ virtual bool DoLaunchProcess(
+ const std::string& channel_name,
+ ScopedHandle* process_exit_event_out) OVERRIDE;
+ virtual void DoKillProcess(DWORD exit_code) OVERRIDE;
+
+ // WtsSessionProcessLauncherImpl implementation.
+ virtual DWORD GetExitCode() OVERRIDE;
+ virtual void ResetUserToken(ScopedHandle* user_token) OVERRIDE;
+ virtual void Stop() OVERRIDE;
+
+ private:
+ // Drains the completion port queue to make sure that all job object
+ // notifications have been received.
+ void DrainJobNotifications();
+
+ // Notified that the completion port queue has been drained.
+ void DrainJobNotificationsCompleted();
+
+ // Creates and initializes the job object that will sandbox the launched child
+ // processes.
+ void InitializeJob();
+
+ // Notified that the job object initialization is complete.
+ void InitializeJobCompleted(scoped_ptr<ScopedHandle> job);
+
+ // Called to process incoming job object notifications.
+ void OnJobNotification(DWORD message, DWORD pid);
+
+ FilePath binary_path_;
+
+ // The task runner all public methods of this class should be called on.
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+
+ // The task runner serving job object notifications.
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ // The job object used to control the lifetime of child processes.
+ ScopedHandle job_;
+
+ // A waiting handle that becomes signalled once all process associated with
+ // the job have been terminated.
+ ScopedHandle process_exit_event_;
+
+ // The token to be used to launch a process in a different session.
+ ScopedHandle user_token_;
+
+ // The handle of the worker process, if launched.
+ ScopedHandle worker_process_;
+
+ DISALLOW_COPY_AND_ASSIGN(ElevatedProcessLauncher);
+};
+
+SingleProcessLauncher::SingleProcessLauncher(
+ const FilePath& binary_path,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
+ : binary_path_(binary_path),
+ main_task_runner_(main_task_runner) {
}
-WtsSessionProcessLauncher::~WtsSessionProcessLauncher() {
- // Make sure that the object is completely stopped. The same check exists
- // in Stoppable::~Stoppable() but this one helps us to fail early and
- // predictably.
- CHECK_EQ(stoppable_state(), Stoppable::kStopped);
+bool SingleProcessLauncher::DoLaunchProcess(
+ const std::string& channel_name,
+ ScopedHandle* process_exit_event_out) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
- monitor_->RemoveWtsConsoleObserver(this);
+ // Create the command line passing the name of the IPC channel to use and
+ // copying known switches from the caller's command line.
+ CommandLine command_line(binary_path_);
+ command_line.AppendSwitchNative(kDaemonIpcSwitchName,
+ UTF8ToWide(channel_name));
+ command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(),
+ kCopiedSwitchNames,
+ _countof(kCopiedSwitchNames));
- CHECK(!attached_);
- CHECK(!timer_.IsRunning());
+ // Try to launch the process and attach an object watcher to the returned
+ // handle so that we get notified when the process terminates.
+ ScopedHandle worker_thread;
+ worker_process_.Close();
+ if (!LaunchProcessWithToken(binary_path_,
+ command_line.GetCommandLineString(),
+ user_token_,
+ 0,
+ &worker_process_,
+ &worker_thread)) {
+ return false;
+ }
+
+ ScopedHandle process_exit_event;
+ if (!DuplicateHandle(GetCurrentProcess(),
+ worker_process_,
+ GetCurrentProcess(),
+ process_exit_event.Receive(),
+ SYNCHRONIZE,
+ FALSE,
+ 0)) {
+ LOG_GETLASTERROR(ERROR) << "Failed to duplicate a handle";
+ DoKillProcess(CONTROL_C_EXIT);
+ return false;
+ }
+
+ *process_exit_event_out = process_exit_event.Pass();
+ return true;
+}
+
+void SingleProcessLauncher::DoKillProcess(DWORD exit_code) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+
+ if (worker_process_.IsValid()) {
+ TerminateProcess(worker_process_, exit_code);
+ }
}
-void WtsSessionProcessLauncher::OnIOCompleted(
+DWORD SingleProcessLauncher::GetExitCode() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+
+ DWORD exit_code = CONTROL_C_EXIT;
+ if (worker_process_.IsValid()) {
+ 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();
+ }
+
+ return exit_code;
+}
+
+void SingleProcessLauncher::ResetUserToken(ScopedHandle* user_token) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+
+ user_token_ = user_token->Pass();
+}
+
+void SingleProcessLauncher::Stop() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+}
+
+ElevatedProcessLauncher::ElevatedProcessLauncher(
+ const FilePath& binary_path,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
+ : binary_path_(binary_path),
+ main_task_runner_(main_task_runner),
+ io_task_runner_(io_task_runner) {
+ process_exit_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
+ CHECK(process_exit_event_.IsValid());
+
+ // To receive job object notifications the job object is registered with
+ // the completion port represented by |io_task_runner|. The registration has
+ // to be done on the I/O thread because MessageLoopForIO::RegisterJobObject()
+ // can only be called via MessageLoopForIO::current().
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ElevatedProcessLauncher::InitializeJob, this));
+}
+
+void ElevatedProcessLauncher::OnIOCompleted(
base::MessagePumpForIO::IOContext* context,
DWORD bytes_transferred,
DWORD error) {
- DCHECK(ipc_message_loop_->BelongsToCurrentThread());
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
// |bytes_transferred| is used in job object notifications to supply
// the message ID; |context| carries process ID.
- main_message_loop_->PostTask(FROM_HERE, base::Bind(
- &WtsSessionProcessLauncher::OnJobNotification,
- base::Unretained(this), bytes_transferred,
+ main_task_runner_->PostTask(FROM_HERE, base::Bind(
+ &ElevatedProcessLauncher::OnJobNotification, this, bytes_transferred,
reinterpret_cast<DWORD>(context)));
}
-bool WtsSessionProcessLauncher::DoLaunchProcess(
+bool ElevatedProcessLauncher::DoLaunchProcess(
const std::string& channel_name,
ScopedHandle* process_exit_event_out) {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
// The job object is not ready. Retry starting the host process later.
if (!job_.IsValid()) {
return false;
}
- // Construct the host binary name.
+ // Construct the helper binary name.
FilePath dir_path;
if (!PathService::Get(base::DIR_EXE, &dir_path)) {
LOG(ERROR) << "Failed to get the executable file name.";
return false;
}
- FilePath host_binary = dir_path.Append(kMe2meHostBinaryName);
FilePath service_binary = dir_path.Append(kMe2meServiceBinaryName);
- // Create the host process command line passing the name of the IPC channel
- // to use and copying known switches from the service's command line.
+ // Create the command line passing the name of the IPC channel to use and
+ // copying known switches from the caller's command line.
CommandLine command_line(service_binary);
- command_line.AppendSwitchPath(kElevateSwitchName, host_binary);
+ command_line.AppendSwitchPath(kElevateSwitchName, binary_path_);
command_line.AppendSwitchNative(kDaemonIpcSwitchName,
UTF8ToWide(channel_name));
command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(),
@@ -150,11 +346,11 @@ bool WtsSessionProcessLauncher::DoLaunchProcess(
// Try to launch the process and attach an object watcher to the returned
// handle so that we get notified when the process terminates.
- base::win::ScopedHandle worker_process;
- base::win::ScopedHandle worker_thread;
+ ScopedHandle worker_process;
+ ScopedHandle worker_thread;
if (!LaunchProcessWithToken(service_binary,
command_line.GetCommandLineString(),
- session_token_,
+ user_token_,
CREATE_SUSPENDED,
&worker_process,
&worker_thread)) {
@@ -190,110 +386,71 @@ bool WtsSessionProcessLauncher::DoLaunchProcess(
return true;
}
-void WtsSessionProcessLauncher::DoKillProcess(DWORD exit_code) {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
+void ElevatedProcessLauncher::DoKillProcess(DWORD exit_code) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
if (job_.IsValid()) {
TerminateJobObject(job_, exit_code);
}
}
-void WtsSessionProcessLauncher::OnChannelConnected() {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
-}
-
-bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
-
- return false;
-}
+DWORD ElevatedProcessLauncher::GetExitCode() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
-void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
+ DWORD exit_code = CONTROL_C_EXIT;
+ if (worker_process_.IsValid()) {
+ if (!::GetExitCodeProcess(worker_process_, &exit_code)) {
+ LOG_GETLASTERROR(INFO)
+ << "Failed to query the exit code of the worker process";
+ exit_code = CONTROL_C_EXIT;
+ }
- if (stoppable_state() != Stoppable::kRunning) {
- return;
+ worker_process_.Close();
}
- DCHECK(!attached_);
- DCHECK(!timer_.IsRunning());
-
- attached_ = true;
-
- // Create a session token for the launched process.
- if (!CreateSessionToken(session_id, &session_token_))
- return;
-
- // Now try to launch the host.
- LaunchProcess();
+ return exit_code;
}
-void WtsSessionProcessLauncher::OnSessionDetached() {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
- DCHECK(attached_);
+void ElevatedProcessLauncher::ResetUserToken(
+ ScopedHandle* user_token) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
- attached_ = false;
- launch_backoff_ = base::TimeDelta();
- session_token_.Close();
- timer_.Stop();
-
- if (launcher_.get() != NULL) {
- launcher_->Stop();
- }
+ user_token_ = user_token->Pass();
}
-void WtsSessionProcessLauncher::DoStop() {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
-
- if (attached_) {
- OnSessionDetached();
- }
-
- job_.Close();
+void ElevatedProcessLauncher::Stop() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
// Drain the completion queue to make sure all job object notification have
// been received.
- if (job_state_ == kJobRunning) {
- job_state_ = kJobStopping;
- ipc_message_loop_->PostTask(FROM_HERE, base::Bind(
- &WtsSessionProcessLauncher::DrainJobNotifications,
- base::Unretained(this)));
- }
-
- // Don't complete shutdown if |launcher_| is not completely stopped.
- if (launcher_.get() != NULL) {
- return;
- }
-
- // Don't complete shutdown if the completion queue hasn't been drained.
- if (job_state_ != kJobUninitialized && job_state_ != kJobStopped) {
- return;
- }
-
- CompleteStopping();
+ DrainJobNotificationsCompleted();
}
-void WtsSessionProcessLauncher::DrainJobNotifications() {
- DCHECK(ipc_message_loop_->BelongsToCurrentThread());
+void ElevatedProcessLauncher::DrainJobNotifications() {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
// DrainJobNotifications() is posted after the job object is destroyed, so
// by this time all notifications from the job object have been processed
// already. Let the main thread know that the queue has been drained.
- main_message_loop_->PostTask(FROM_HERE, base::Bind(
- &WtsSessionProcessLauncher::DrainJobNotificationsCompleted,
- base::Unretained(this)));
+ main_task_runner_->PostTask(FROM_HERE, base::Bind(
+ &ElevatedProcessLauncher::DrainJobNotificationsCompleted, this));
}
-void WtsSessionProcessLauncher::DrainJobNotificationsCompleted() {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
- DCHECK_EQ(job_state_, kJobStopping);
+void ElevatedProcessLauncher::DrainJobNotificationsCompleted() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+
+ if (job_.IsValid()) {
+ job_.Close();
- job_state_ = kJobStopped;
- Stop();
+ // Drain the completion queue to make sure all job object notification have
+ // been received.
+ io_task_runner_->PostTask(FROM_HERE, base::Bind(
+ &ElevatedProcessLauncher::DrainJobNotifications, this));
+ }
}
-void WtsSessionProcessLauncher::InitializeJob() {
- DCHECK(ipc_message_loop_->BelongsToCurrentThread());
+void ElevatedProcessLauncher::InitializeJob() {
+ DCHECK(io_task_runner_->BelongsToCurrentThread());
ScopedHandle job;
job.Set(CreateJobObject(NULL, NULL));
@@ -332,25 +489,21 @@ void WtsSessionProcessLauncher::InitializeJob() {
*job_wrapper = job.Pass();
// Let the main thread know that initialization is complete.
- main_message_loop_->PostTask(FROM_HERE, base::Bind(
- &WtsSessionProcessLauncher::InitializeJobCompleted,
- base::Unretained(this), base::Passed(&job_wrapper)));
+ main_task_runner_->PostTask(FROM_HERE, base::Bind(
+ &ElevatedProcessLauncher::InitializeJobCompleted, this,
+ base::Passed(&job_wrapper)));
}
-void WtsSessionProcessLauncher::InitializeJobCompleted(
+void ElevatedProcessLauncher::InitializeJobCompleted(
scoped_ptr<ScopedHandle> job) {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
DCHECK(!job_.IsValid());
- DCHECK_EQ(job_state_, kJobUninitialized);
- if (stoppable_state() == Stoppable::kRunning) {
- job_ = job->Pass();
- job_state_ = kJobRunning;
- }
+ job_ = job->Pass();
}
-void WtsSessionProcessLauncher::OnJobNotification(DWORD message, DWORD pid) {
- DCHECK(main_message_loop_->BelongsToCurrentThread());
+void ElevatedProcessLauncher::OnJobNotification(DWORD message, DWORD pid) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
switch (message) {
case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
@@ -366,6 +519,127 @@ void WtsSessionProcessLauncher::OnJobNotification(DWORD message, DWORD pid) {
}
}
+} // namespace
+
+WtsSessionProcessLauncherImpl::~WtsSessionProcessLauncherImpl() {
+}
+
+WtsSessionProcessLauncher::WtsSessionProcessLauncher(
+ const base::Closure& stopped_callback,
+ WtsConsoleMonitor* monitor,
+ scoped_refptr<base::SingleThreadTaskRunner> main_message_loop,
+ scoped_refptr<base::SingleThreadTaskRunner> ipc_message_loop)
+ : Stoppable(main_message_loop, stopped_callback),
+ attached_(false),
+ main_message_loop_(main_message_loop),
+ ipc_message_loop_(ipc_message_loop),
+ monitor_(monitor) {
+ monitor_->AddWtsConsoleObserver(this);
+
+ // Construct the host binary name.
+ FilePath dir_path;
+ if (!PathService::Get(base::DIR_EXE, &dir_path)) {
+ LOG(ERROR) << "Failed to get the executable file name.";
+ Stop();
+ return;
+ }
+ FilePath host_binary = dir_path.Append(kMe2meHostBinaryName);
+
+ // The workaround we use to launch a process in a not yet logged in session
+ // (see CreateRemoteSessionProcess()) on Windows XP/2K3 does not let us to
+ // assign the started process to a job. However on Vista+ we have to start
+ // the host via a helper process. The helper process calls ShellExecute() that
+ // does not work across the session boundary but it required to launch
+ // a binary specifying uiAccess='true' in its manifest.
+ //
+ // Below we choose which implementation of |WorkerProcessLauncher::Delegate|
+ // to use. A single process is launched on XP (since uiAccess='true' does not
+ // have effect any way). Vista+ utilizes a helper process and assign it to
+ // a job object to control it.
+ if (base::win::GetVersion() == base::win::VERSION_XP) {
+ impl_ = new SingleProcessLauncher(host_binary, main_message_loop);
+ } else {
+ impl_ = new ElevatedProcessLauncher(host_binary, main_message_loop,
+ ipc_message_loop);
+ }
+}
+
+WtsSessionProcessLauncher::~WtsSessionProcessLauncher() {
+ // Make sure that the object is completely stopped. The same check exists
+ // in Stoppable::~Stoppable() but this one helps us to fail early and
+ // predictably.
+ CHECK_EQ(stoppable_state(), Stoppable::kStopped);
+
+ monitor_->RemoveWtsConsoleObserver(this);
+
+ CHECK(!attached_);
+ CHECK(!timer_.IsRunning());
+}
+
+void WtsSessionProcessLauncher::OnChannelConnected() {
+ DCHECK(main_message_loop_->BelongsToCurrentThread());
+}
+
+bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) {
+ DCHECK(main_message_loop_->BelongsToCurrentThread());
+
+ return false;
+}
+
+void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) {
+ DCHECK(main_message_loop_->BelongsToCurrentThread());
+
+ if (stoppable_state() != Stoppable::kRunning) {
+ return;
+ }
+
+ DCHECK(!attached_);
+ DCHECK(!timer_.IsRunning());
+
+ attached_ = true;
+
+ // Create a session token and launch the host.
+ ScopedHandle user_token;
+ if (CreateSessionToken(session_id, &user_token)) {
+ impl_->ResetUserToken(&user_token);
+ LaunchProcess();
+ }
+}
+
+void WtsSessionProcessLauncher::OnSessionDetached() {
+ DCHECK(main_message_loop_->BelongsToCurrentThread());
+ DCHECK(attached_);
+
+ attached_ = false;
+ launch_backoff_ = base::TimeDelta();
+ timer_.Stop();
+
+ if (launcher_.get() != NULL) {
+ launcher_->Stop();
+ }
+}
+
+void WtsSessionProcessLauncher::DoStop() {
+ DCHECK(main_message_loop_->BelongsToCurrentThread());
+
+ if (attached_) {
+ OnSessionDetached();
+ }
+
+ // Don't complete shutdown if |launcher_| is not completely stopped.
+ if (launcher_.get() != NULL) {
+ return;
+ }
+
+ // Tear down the core asynchromously.
+ if (impl_.get()) {
+ impl_->Stop();
+ impl_ = NULL;
+ }
+
+ CompleteStopping();
+}
+
void WtsSessionProcessLauncher::LaunchProcess() {
DCHECK(main_message_loop_->BelongsToCurrentThread());
DCHECK(attached_);
@@ -374,7 +648,7 @@ void WtsSessionProcessLauncher::LaunchProcess() {
launch_time_ = base::Time::Now();
launcher_.reset(new WorkerProcessLauncher(
- this, this,
+ impl_.get(), this,
base::Bind(&WtsSessionProcessLauncher::OnLauncherStopped,
base::Unretained(this)),
main_message_loop_,
@@ -385,16 +659,8 @@ void WtsSessionProcessLauncher::LaunchProcess() {
void WtsSessionProcessLauncher::OnLauncherStopped() {
DCHECK(main_message_loop_->BelongsToCurrentThread());
- DWORD exit_code = CONTROL_C_EXIT;
- if (worker_process_.IsValid()) {
- 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();
- }
+ // Retrieve the exit code of the worker process.
+ DWORD exit_code = impl_->GetExitCode();
launcher_.reset(NULL);
« no previous file with comments | « remoting/host/win/wts_session_process_launcher.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698