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

Side by Side Diff: remoting/host/win/wts_session_process_launcher.cc

Issue 10828181: [Chromoting] Moving common logic responsible for launching child processes to WorkerProcessLauncher… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 // This file implements the Windows service controlling Me2Me host processes 5 // This file implements the Windows service controlling Me2Me host processes
6 // running within user sessions. 6 // running within user sessions.
7 7
8 #include "remoting/host/win/wts_session_process_launcher.h" 8 #include "remoting/host/win/wts_session_process_launcher.h"
9 9
10 #include <windows.h> 10 #include <windows.h>
11 #include <sddl.h> 11 #include <sddl.h>
12 #include <limits> 12 #include <limits>
13 13
14 #include "base/base_switches.h" 14 #include "base/base_switches.h"
15 #include "base/bind.h" 15 #include "base/bind.h"
16 #include "base/bind_helpers.h" 16 #include "base/bind_helpers.h"
17 #include "base/command_line.h" 17 #include "base/command_line.h"
18 #include "base/file_path.h" 18 #include "base/file_path.h"
19 #include "base/file_util.h" 19 #include "base/file_util.h"
20 #include "base/logging.h" 20 #include "base/logging.h"
21 #include "base/single_thread_task_runner.h" 21 #include "base/single_thread_task_runner.h"
22 #include "base/path_service.h" 22 #include "base/path_service.h"
23 #include "base/process_util.h" 23 #include "base/process_util.h"
24 #include "base/rand_util.h" 24 #include "base/rand_util.h"
25 #include "base/stringprintf.h" 25 #include "base/stringprintf.h"
26 #include "base/utf_string_conversions.h"
26 #include "base/win/scoped_handle.h" 27 #include "base/win/scoped_handle.h"
27 #include "ipc/ipc_channel_proxy.h" 28 #include "ipc/ipc_channel_proxy.h"
28 #include "ipc/ipc_message.h" 29 #include "ipc/ipc_message.h"
29 #include "ipc/ipc_message_macros.h" 30 #include "ipc/ipc_message_macros.h"
30 #include "remoting/host/constants.h" 31 #include "remoting/host/constants.h"
31 #include "remoting/host/chromoting_messages.h" 32 #include "remoting/host/chromoting_messages.h"
32 #include "remoting/host/sas_injector.h" 33 #include "remoting/host/sas_injector.h"
33 #include "remoting/host/win/launch_process_with_token.h" 34 #include "remoting/host/win/launch_process_with_token.h"
34 #include "remoting/host/win/wts_console_monitor.h" 35 #include "remoting/host/win/wts_console_monitor.h"
35 36
36 using base::win::ScopedHandle; 37 using base::win::ScopedHandle;
37 using base::TimeDelta; 38 using base::TimeDelta;
38 39
39 namespace { 40 namespace {
40 41
41 // The minimum and maximum delays between attempts to inject host process into 42 // The minimum and maximum delays between attempts to inject host process into
42 // a session. 43 // a session.
43 const int kMaxLaunchDelaySeconds = 60; 44 const int kMaxLaunchDelaySeconds = 60;
44 const int kMinLaunchDelaySeconds = 1; 45 const int kMinLaunchDelaySeconds = 1;
45 46
46 const FilePath::CharType kMe2meHostBinaryName[] = 47 const FilePath::CharType kMe2meHostBinaryName[] =
47 FILE_PATH_LITERAL("remoting_me2me_host.exe"); 48 FILE_PATH_LITERAL("remoting_me2me_host.exe");
48 49
49 // Match the pipe name prefix used by Chrome IPC channels.
50 const wchar_t kChromePipeNamePrefix[] = L"\\\\.\\pipe\\chrome.";
51
52 // The IPC channel name is passed to the host in the command line. 50 // The IPC channel name is passed to the host in the command line.
53 const char kChromotingIpcSwitchName[] = "chromoting-ipc"; 51 const char kChromotingIpcSwitchName[] = "chromoting-ipc";
54 52
55 // The command line parameters that should be copied from the service's command 53 // The command line parameters that should be copied from the service's command
56 // line to the host process. 54 // line to the host process.
57 const char* kCopiedSwitchNames[] = { 55 const char* kCopiedSwitchNames[] = {
58 "auth-config", "host-config", switches::kV, switches::kVModule }; 56 "auth-config", "host-config", switches::kV, switches::kVModule };
59 57
60 // The security descriptor of the Chromoting IPC channel. It gives full access 58 // The security descriptor of the Chromoting IPC channel. It gives full access
61 // to LocalSystem and denies access by anyone else. 59 // to LocalSystem and denies access by anyone else.
62 const wchar_t kChromotingChannelSecurityDescriptor[] = 60 const char kChromotingChannelSecurityDescriptor[] = "O:SYG:SYD:(A;;GA;;;SY)";
63 L"O:SYG:SYD:(A;;GA;;;SY)";
64
65 // Generates random channel ID.
66 // N.B. Stolen from src/content/common/child_process_host_impl.cc
67 std::wstring GenerateRandomChannelId(void* instance) {
68 return base::StringPrintf(L"%d.%p.%d",
69 base::GetCurrentProcId(), instance,
70 base::RandInt(0, std::numeric_limits<int>::max()));
71 }
72
73 // Creates the server end of the Chromoting IPC channel.
74 // N.B. This code is based on IPC::Channel's implementation.
75 bool CreatePipeForIpcChannel(void* instance,
76 std::wstring* channel_name_out,
77 ScopedHandle* pipe_out) {
78 // Create security descriptor for the channel.
79 SECURITY_ATTRIBUTES security_attributes;
80 security_attributes.nLength = sizeof(security_attributes);
81 security_attributes.bInheritHandle = FALSE;
82
83 ULONG security_descriptor_length = 0;
84 if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
85 kChromotingChannelSecurityDescriptor,
86 SDDL_REVISION_1,
87 reinterpret_cast<PSECURITY_DESCRIPTOR*>(
88 &security_attributes.lpSecurityDescriptor),
89 &security_descriptor_length)) {
90 LOG_GETLASTERROR(ERROR) <<
91 "Failed to create a security descriptor for the Chromoting IPC channel";
92 return false;
93 }
94
95 // Generate a random channel name.
96 std::wstring channel_name(GenerateRandomChannelId(instance));
97
98 // Convert it to the pipe name.
99 std::wstring pipe_name(kChromePipeNamePrefix);
100 pipe_name.append(channel_name);
101
102 // Create the server end of the pipe. This code should match the code in
103 // IPC::Channel with exception of passing a non-default security descriptor.
104 HANDLE pipe = CreateNamedPipeW(pipe_name.c_str(),
105 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
106 FILE_FLAG_FIRST_PIPE_INSTANCE,
107 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
108 1,
109 IPC::Channel::kReadBufferSize,
110 IPC::Channel::kReadBufferSize,
111 5000,
112 &security_attributes);
113 if (pipe == INVALID_HANDLE_VALUE) {
114 LOG_GETLASTERROR(ERROR) <<
115 "Failed to create the server end of the Chromoting IPC channel";
116 LocalFree(security_attributes.lpSecurityDescriptor);
117 return false;
118 }
119
120 LocalFree(security_attributes.lpSecurityDescriptor);
121
122 *channel_name_out = channel_name;
123 pipe_out->Set(pipe);
124 return true;
125 }
126 61
127 } // namespace 62 } // namespace
128 63
129 namespace remoting { 64 namespace remoting {
130 65
131 WtsSessionProcessLauncher::WtsSessionProcessLauncher( 66 WtsSessionProcessLauncher::WtsSessionProcessLauncher(
132 const base::Closure& stopped_callback, 67 const base::Closure& stopped_callback,
133 WtsConsoleMonitor* monitor, 68 WtsConsoleMonitor* monitor,
134 scoped_refptr<base::SingleThreadTaskRunner> main_message_loop, 69 scoped_refptr<base::SingleThreadTaskRunner> main_message_loop,
135 scoped_refptr<base::SingleThreadTaskRunner> ipc_message_loop) 70 scoped_refptr<base::SingleThreadTaskRunner> ipc_message_loop)
136 : Stoppable(main_message_loop, stopped_callback), 71 : Stoppable(main_message_loop, stopped_callback),
72 attached_(false),
137 main_message_loop_(main_message_loop), 73 main_message_loop_(main_message_loop),
138 ipc_message_loop_(ipc_message_loop), 74 ipc_message_loop_(ipc_message_loop),
139 monitor_(monitor), 75 monitor_(monitor) {
140 state_(StateDetached) {
141 monitor_->AddWtsConsoleObserver(this); 76 monitor_->AddWtsConsoleObserver(this);
142 } 77 }
143 78
144 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() { 79 WtsSessionProcessLauncher::~WtsSessionProcessLauncher() {
145 monitor_->RemoveWtsConsoleObserver(this); 80 monitor_->RemoveWtsConsoleObserver(this);
146 if (state_ != StateDetached) {
147 OnSessionDetached();
148 }
149 81
150 DCHECK(state_ == StateDetached); 82 DCHECK(!attached_);
151 DCHECK(!timer_.IsRunning()); 83 DCHECK(!timer_.IsRunning());
152 DCHECK(process_.handle() == NULL);
153 DCHECK(process_watcher_.GetWatchedObject() == NULL);
154 DCHECK(chromoting_channel_.get() == NULL);
155 } 84 }
156 85
157 void WtsSessionProcessLauncher::LaunchProcess() { 86 void WtsSessionProcessLauncher::LaunchProcess() {
158 DCHECK(main_message_loop_->BelongsToCurrentThread()); 87 DCHECK(main_message_loop_->BelongsToCurrentThread());
159 DCHECK(state_ == StateStarting); 88 DCHECK(attached_);
89 DCHECK(launcher_.get() == NULL);
160 DCHECK(!timer_.IsRunning()); 90 DCHECK(!timer_.IsRunning());
161 DCHECK(process_.handle() == NULL); 91 DCHECK(!worker_process_.IsValid());
162 DCHECK(process_watcher_.GetWatchedObject() == NULL);
163 DCHECK(chromoting_channel_.get() == NULL);
164 92
165 launch_time_ = base::Time::Now(); 93 launch_time_ = base::Time::Now();
94 launcher_.reset(new WorkerProcessLauncher(
95 base::Bind(&WtsSessionProcessLauncher::OnLauncherStopped,
96 base::Unretained(this)),
97 main_message_loop_,
98 ipc_message_loop_));
99 launcher_->Start(this, kChromotingChannelSecurityDescriptor);
100 }
101
102 void WtsSessionProcessLauncher::OnLauncherStopped() {
103 DCHECK(main_message_loop_->BelongsToCurrentThread());
104
105 DWORD exit_code;
106 if (!::GetExitCodeProcess(worker_process_, &exit_code)) {
Wez 2012/08/08 20:13:41 nit: Info-log GetLastError(), in case we hit some
alexeypa (please no reviews) 2012/08/08 21:49:58 Done.
107 exit_code = CONTROL_C_EXIT;
108 }
109
110 launcher_.reset(NULL);
111 worker_process_.Close();
112
113 // Complete stoppping is shutdown is in progress.
Wez 2012/08/08 20:13:41 typo: stopping typo: is
Wez 2012/08/08 20:13:41 nit: We use "Finish" rather than "Complete" elsewh
Wez 2012/08/08 20:13:41 nit: Reword the comment to clarify _why_ we call C
alexeypa (please no reviews) 2012/08/08 21:49:58 Done.
114 if (stoppable_state() != Stoppable::kRunning) {
115 CompleteStopping();
116 return;
117 }
118
119 // Stop trying to restart the host if its process exited due to
120 // misconfiguration.
121 if (kMinPermanentErrorExitCode <= exit_code &&
122 exit_code <= kMaxPermanentErrorExitCode) {
123 Stop();
124 return;
125 }
126
127 // Try to restart the process if we are still attached to the session.
Wez 2012/08/08 20:13:41 nit: the session -> a session
alexeypa (please no reviews) 2012/08/08 21:49:58 Done.
128 if (attached_) {
129 // Expand the backoff interval if the process has died quickly or reset it
130 // if it was up longer than the maximum backoff delay.
131 base::TimeDelta delta = base::Time::Now() - launch_time_;
132 if (delta < base::TimeDelta() ||
133 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) {
134 launch_backoff_ = base::TimeDelta();
135 } else {
136 launch_backoff_ = std::max(
137 launch_backoff_ * 2, TimeDelta::FromSeconds(kMinLaunchDelaySeconds));
138 launch_backoff_ = std::min(
139 launch_backoff_, TimeDelta::FromSeconds(kMaxLaunchDelaySeconds));
140 }
141
142 // Try to restart the host.
Wez 2012/08/08 20:13:41 nit: "Try to launch the session process."
alexeypa (please no reviews) 2012/08/08 21:49:58 Done.
143 timer_.Start(FROM_HERE, launch_backoff_,
144 this, &WtsSessionProcessLauncher::LaunchProcess);
145 }
146 }
147
148 bool WtsSessionProcessLauncher::DoLaunchProcess(const std::string& channel_name,
149 ScopedHandle* wait_out) {
150 DCHECK(main_message_loop_->BelongsToCurrentThread());
151 DCHECK(!worker_process_.IsValid());
166 152
167 // Construct the host binary name. 153 // Construct the host binary name.
168 FilePath dir_path; 154 FilePath dir_path;
169 if (!PathService::Get(base::DIR_EXE, &dir_path)) { 155 if (!PathService::Get(base::DIR_EXE, &dir_path)) {
170 LOG(ERROR) << "Failed to get the executable file name."; 156 LOG(ERROR) << "Failed to get the executable file name.";
171 Stop(); 157 return false;
172 return;
173 } 158 }
174 FilePath host_binary = dir_path.Append(kMe2meHostBinaryName); 159 FilePath host_binary = dir_path.Append(kMe2meHostBinaryName);
175 160
176 std::wstring channel_name; 161 // Create the host process command line passing the name of the IPC channel
177 ScopedHandle pipe; 162 // to use and copying known switches from the service's command line.
178 if (CreatePipeForIpcChannel(this, &channel_name, &pipe)) { 163 CommandLine command_line(host_binary);
179 // Wrap the pipe into an IPC channel. 164 command_line.AppendSwitchNative(kChromotingIpcSwitchName,
180 chromoting_channel_.reset(new IPC::ChannelProxy( 165 UTF8ToWide(channel_name));
181 IPC::ChannelHandle(pipe.Get()), 166 command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(),
182 IPC::Channel::MODE_SERVER, 167 kCopiedSwitchNames,
183 this, 168 _countof(kCopiedSwitchNames));
184 ipc_message_loop_));
185 169
186 // Create the host process command line passing the name of the IPC channel 170 // Try to launch the process and attach an object watcher to the returned
187 // to use and copying known switches from the service's command line. 171 // handle so that we get notified when the process terminates.
188 CommandLine command_line(host_binary); 172 if (!LaunchProcessWithToken(host_binary,
189 command_line.AppendSwitchNative(kChromotingIpcSwitchName, channel_name); 173 command_line.GetCommandLineString(),
190 command_line.CopySwitchesFrom(*CommandLine::ForCurrentProcess(), 174 session_token_,
191 kCopiedSwitchNames, 175 &worker_process_)) {
192 _countof(kCopiedSwitchNames)); 176 return false;
193
194 // Try to launch the process and attach an object watcher to the returned
195 // handle so that we get notified when the process terminates.
196 if (LaunchProcessWithToken(host_binary,
197 command_line.GetCommandLineString(),
198 session_token_,
199 &process_)) {
200 if (process_watcher_.StartWatching(process_.handle(), this)) {
201 state_ = StateAttached;
202 return;
203 } else {
204 LOG(ERROR) << "Failed to arm the process watcher.";
205 process_.Terminate(0);
206 process_.Close();
207 }
208 }
209
210 chromoting_channel_.reset();
211 } 177 }
212 178
213 // Something went wrong. Try to launch the host again later. The attempts rate 179 ScopedHandle wait;
214 // is limited by exponential backoff. 180 if (!DuplicateHandle(GetCurrentProcess(),
215 launch_backoff_ = std::max(launch_backoff_ * 2, 181 worker_process_,
216 TimeDelta::FromSeconds(kMinLaunchDelaySeconds)); 182 GetCurrentProcess(),
217 launch_backoff_ = std::min(launch_backoff_, 183 wait.Receive(),
218 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)); 184 SYNCHRONIZE,
219 timer_.Start(FROM_HERE, launch_backoff_, 185 FALSE,
220 this, &WtsSessionProcessLauncher::LaunchProcess); 186 0)) {
187 LOG_GETLASTERROR(ERROR) << "Failed to duplicate a handle";
188 DoKillProcess(CONTROL_C_EXIT);
189 return false;
190 }
191
192 *wait_out = wait.Pass();
193 return true;
221 } 194 }
222 195
223 void WtsSessionProcessLauncher::OnObjectSignaled(HANDLE object) { 196 void WtsSessionProcessLauncher::DoKillProcess(DWORD exit_code) {
224 if (!main_message_loop_->BelongsToCurrentThread()) { 197 DCHECK(main_message_loop_->BelongsToCurrentThread());
225 main_message_loop_->PostTask( 198
226 FROM_HERE, base::Bind(&WtsSessionProcessLauncher::OnObjectSignaled, 199 if (worker_process_.IsValid()) {
227 base::Unretained(this), object)); 200 TerminateProcess(worker_process_, exit_code);
228 return;
229 } 201 }
202 }
230 203
231 // It is possible that OnObjectSignaled() task will be queued by another 204 void WtsSessionProcessLauncher::OnChannelConnected(
232 // thread right before |process_watcher_| was stopped. It such a case it is 205 base::win::ScopedHandle peer) {
233 // safe to ignore this notification. 206 DCHECK(main_message_loop_->BelongsToCurrentThread());
234 if (state_ != StateAttached) { 207
235 return; 208 DWORD client_process_id = GetProcessId(peer);
209 DWORD expected_process_id = GetProcessId(worker_process_);
210 if (client_process_id != expected_process_id) {
211 LOG(ERROR)
212 << "Unexpected client connected: expected=" << expected_process_id
213 << ", actual=" << client_process_id;
214 Stop();
236 } 215 }
237
238 DCHECK(!timer_.IsRunning());
239 DCHECK(process_.handle() != NULL);
240 DCHECK(process_watcher_.GetWatchedObject() == NULL);
241 DCHECK(chromoting_channel_.get() != NULL);
242
243 // Stop trying to restart the host if its process exited due to
244 // misconfiguration.
245 int exit_code;
246 bool stop_trying =
247 base::WaitForExitCodeWithTimeout(
248 process_.handle(), &exit_code, base::TimeDelta()) &&
249 kMinPermanentErrorExitCode <= exit_code &&
250 exit_code <= kMaxPermanentErrorExitCode;
251
252 // The host process has been terminated for some reason. The handle can now be
253 // closed.
254 process_.Close();
255 chromoting_channel_.reset();
256 state_ = StateStarting;
257
258 if (stop_trying) {
259 Stop();
260 return;
261 }
262
263 // Expand the backoff interval if the process has died quickly or reset it if
264 // it was up longer than the maximum backoff delay.
265 base::TimeDelta delta = base::Time::Now() - launch_time_;
266 if (delta < base::TimeDelta() ||
267 delta >= base::TimeDelta::FromSeconds(kMaxLaunchDelaySeconds)) {
268 launch_backoff_ = base::TimeDelta();
269 } else {
270 launch_backoff_ = std::max(launch_backoff_ * 2,
271 TimeDelta::FromSeconds(kMinLaunchDelaySeconds));
272 launch_backoff_ = std::min(launch_backoff_,
273 TimeDelta::FromSeconds(kMaxLaunchDelaySeconds));
274 }
275
276 // Try to restart the host.
277 timer_.Start(FROM_HERE, launch_backoff_,
278 this, &WtsSessionProcessLauncher::LaunchProcess);
279 } 216 }
280 217
281 bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) { 218 bool WtsSessionProcessLauncher::OnMessageReceived(const IPC::Message& message) {
219 DCHECK(main_message_loop_->BelongsToCurrentThread());
220
282 bool handled = true; 221 bool handled = true;
283 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message) 222 IPC_BEGIN_MESSAGE_MAP(WtsSessionProcessLauncher, message)
284 IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole, 223 IPC_MESSAGE_HANDLER(ChromotingHostMsg_SendSasToConsole,
285 OnSendSasToConsole) 224 OnSendSasToConsole)
286 IPC_MESSAGE_UNHANDLED(handled = false) 225 IPC_MESSAGE_UNHANDLED(handled = false)
287 IPC_END_MESSAGE_MAP() 226 IPC_END_MESSAGE_MAP()
288 return handled; 227 return handled;
289 } 228 }
290 229
291 void WtsSessionProcessLauncher::OnSendSasToConsole() { 230 void WtsSessionProcessLauncher::OnSendSasToConsole() {
292 if (!main_message_loop_->BelongsToCurrentThread()) { 231 DCHECK(main_message_loop_->BelongsToCurrentThread());
293 main_message_loop_->PostTask(
294 FROM_HERE, base::Bind(&WtsSessionProcessLauncher::OnSendSasToConsole,
295 base::Unretained(this)));
296 return;
297 }
298 232
299 if (state_ == StateAttached) { 233 if (attached_) {
300 if (sas_injector_.get() == NULL) { 234 if (sas_injector_.get() == NULL) {
301 sas_injector_ = SasInjector::Create(); 235 sas_injector_ = SasInjector::Create();
302 } 236 }
303 237
304 if (sas_injector_.get() != NULL) { 238 if (sas_injector_.get() != NULL) {
305 sas_injector_->InjectSas(); 239 sas_injector_->InjectSas();
306 } 240 }
307 } 241 }
308 } 242 }
309 243
310 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) { 244 void WtsSessionProcessLauncher::OnSessionAttached(uint32 session_id) {
311 DCHECK(main_message_loop_->BelongsToCurrentThread()); 245 DCHECK(main_message_loop_->BelongsToCurrentThread());
312 246
313 if (stoppable_state() != Stoppable::kRunning) { 247 if (stoppable_state() != Stoppable::kRunning) {
314 return; 248 return;
315 } 249 }
316 250
317 DCHECK(state_ == StateDetached); 251 DCHECK(!attached_);
318 DCHECK(!timer_.IsRunning()); 252 DCHECK(!timer_.IsRunning());
319 DCHECK(process_.handle() == NULL); 253
320 DCHECK(process_watcher_.GetWatchedObject() == NULL); 254 attached_ = true;
321 DCHECK(chromoting_channel_.get() == NULL);
322 255
323 // Create a session token for the launched process. 256 // Create a session token for the launched process.
324 if (!CreateSessionToken(session_id, &session_token_)) 257 if (!CreateSessionToken(session_id, &session_token_))
325 return; 258 return;
326 259
327 // Now try to launch the host. 260 // Now try to launch the host.
328 state_ = StateStarting;
329 LaunchProcess(); 261 LaunchProcess();
330 } 262 }
331 263
332 void WtsSessionProcessLauncher::OnSessionDetached() { 264 void WtsSessionProcessLauncher::OnSessionDetached() {
333 DCHECK(main_message_loop_->BelongsToCurrentThread()); 265 DCHECK(main_message_loop_->BelongsToCurrentThread());
334 DCHECK(state_ == StateDetached || 266 DCHECK(attached_);
335 state_ == StateStarting ||
336 state_ == StateAttached);
337 267
338 switch (state_) { 268 attached_ = false;
339 case StateDetached: 269 launch_backoff_ = base::TimeDelta();
340 DCHECK(!timer_.IsRunning()); 270 session_token_.Close();
341 DCHECK(process_.handle() == NULL); 271 timer_.Stop();
342 DCHECK(process_watcher_.GetWatchedObject() == NULL);
343 DCHECK(chromoting_channel_.get() == NULL);
344 break;
345 272
346 case StateStarting: 273 if (launcher_.get() != NULL) {
347 DCHECK(process_.handle() == NULL); 274 launcher_->Stop();
348 DCHECK(process_watcher_.GetWatchedObject() == NULL);
349 DCHECK(chromoting_channel_.get() == NULL);
350
351 timer_.Stop();
352 launch_backoff_ = base::TimeDelta();
353 state_ = StateDetached;
354 break;
355
356 case StateAttached:
357 DCHECK(!timer_.IsRunning());
358 DCHECK(process_.handle() != NULL);
359 DCHECK(process_watcher_.GetWatchedObject() != NULL);
360 DCHECK(chromoting_channel_.get() != NULL);
361
362 process_watcher_.StopWatching();
363 process_.Terminate(0);
364 process_.Close();
365 chromoting_channel_.reset();
366 state_ = StateDetached;
367 break;
368 } 275 }
369
370 session_token_.Close();
371 } 276 }
372 277
373 void WtsSessionProcessLauncher::DoStop() { 278 void WtsSessionProcessLauncher::DoStop() {
374 if (state_ != StateDetached) { 279 DCHECK(main_message_loop_->BelongsToCurrentThread());
280
281 if (attached_) {
375 OnSessionDetached(); 282 OnSessionDetached();
376 } 283 }
377 284
378 CompleteStopping(); 285 if (launcher_.get() == NULL) {
286 CompleteStopping();
287 }
379 } 288 }
380 289
381 } // namespace remoting 290 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698