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

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

Issue 10829467: [Chromoting] Introducing refcount-based life time management of the message loops in the service (d… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebased 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/host/win/host_service.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/host_service.h" 8 #include "remoting/host/win/host_service.h"
9 9
10 #include <windows.h> 10 #include <windows.h>
11 #include <shellapi.h> 11 #include <shellapi.h>
12 #include <wtsapi32.h> 12 #include <wtsapi32.h>
13 13
14 #include "base/at_exit.h" 14 #include "base/at_exit.h"
15 #include "base/base_paths.h" 15 #include "base/base_paths.h"
16 #include "base/base_switches.h" 16 #include "base/base_switches.h"
17 #include "base/bind.h" 17 #include "base/bind.h"
18 #include "base/command_line.h" 18 #include "base/command_line.h"
19 #include "base/file_path.h" 19 #include "base/file_path.h"
20 #include "base/logging.h" 20 #include "base/logging.h"
21 #include "base/message_loop.h" 21 #include "base/message_loop.h"
22 #include "base/single_thread_task_runner.h" 22 #include "base/single_thread_task_runner.h"
23 #include "base/stringprintf.h" 23 #include "base/stringprintf.h"
24 #include "base/threading/thread.h" 24 #include "base/threading/thread.h"
25 #include "base/utf_string_conversions.h" 25 #include "base/utf_string_conversions.h"
26 #include "base/win/wrapped_window_proc.h" 26 #include "base/win/wrapped_window_proc.h"
27 #include "remoting/base/auto_thread_task_runner.h"
27 #include "remoting/base/breakpad.h" 28 #include "remoting/base/breakpad.h"
28 #include "remoting/base/scoped_sc_handle_win.h" 29 #include "remoting/base/scoped_sc_handle_win.h"
29 #include "remoting/base/stoppable.h" 30 #include "remoting/base/stoppable.h"
30 #include "remoting/host/branding.h" 31 #include "remoting/host/branding.h"
31 32
32 #if defined(REMOTING_MULTI_PROCESS) 33 #if defined(REMOTING_MULTI_PROCESS)
33 #include "remoting/host/daemon_process.h" 34 #include "remoting/host/daemon_process.h"
34 #endif // defined(REMOTING_MULTI_PROCESS) 35 #endif // defined(REMOTING_MULTI_PROCESS)
35 36
36 #include "remoting/host/usage_stats_consent.h" 37 #include "remoting/host/usage_stats_consent.h"
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 // Exit codes: 86 // Exit codes:
86 const int kSuccessExitCode = 0; 87 const int kSuccessExitCode = 0;
87 const int kUsageExitCode = 1; 88 const int kUsageExitCode = 1;
88 const int kErrorExitCode = 2; 89 const int kErrorExitCode = 2;
89 90
90 void usage(const FilePath& program_name) { 91 void usage(const FilePath& program_name) {
91 LOG(INFO) << StringPrintf(kUsageMessage, 92 LOG(INFO) << StringPrintf(kUsageMessage,
92 UTF16ToWide(program_name.value()).c_str()); 93 UTF16ToWide(program_name.value()).c_str());
93 } 94 }
94 95
96 void QuitMessageLoop(MessageLoop* message_loop) {
97 message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure());
98 }
99
95 } // namespace 100 } // namespace
96 101
97 namespace remoting { 102 namespace remoting {
98 103
99 HostService::HostService() : 104 HostService::HostService() :
100 console_session_id_(kInvalidSessionId), 105 console_session_id_(kInvalidSessionId),
101 run_routine_(&HostService::RunAsService), 106 run_routine_(&HostService::RunAsService),
102 service_status_handle_(0), 107 service_status_handle_(0),
103 stopped_event_(true, false) { 108 stopped_event_(true, false) {
104 } 109 }
105 110
106 HostService::~HostService() { 111 HostService::~HostService() {
107 } 112 }
108 113
109 void HostService::AddWtsConsoleObserver(WtsConsoleObserver* observer) { 114 void HostService::AddWtsConsoleObserver(WtsConsoleObserver* observer) {
110 DCHECK(main_task_runner_->BelongsToCurrentThread()); 115 DCHECK(main_task_runner_->BelongsToCurrentThread());
111 116
112 console_observers_.AddObserver(observer); 117 console_observers_.AddObserver(observer);
113 } 118 }
114 119
115 void HostService::RemoveWtsConsoleObserver(WtsConsoleObserver* observer) { 120 void HostService::RemoveWtsConsoleObserver(WtsConsoleObserver* observer) {
116 DCHECK(main_task_runner_->BelongsToCurrentThread()); 121 DCHECK(main_task_runner_->BelongsToCurrentThread());
117 122
118 console_observers_.RemoveObserver(observer); 123 console_observers_.RemoveObserver(observer);
119 } 124 }
120 125
121 void HostService::OnChildStopped() { 126 void HostService::OnChildStopped() {
122 child_.reset(NULL); 127 child_.reset(NULL);
123 main_task_runner_->PostTask(FROM_HERE, MessageLoop::QuitClosure()); 128 main_task_runner_ = NULL;
124 } 129 }
125 130
126 void HostService::OnSessionChange() { 131 void HostService::OnSessionChange() {
127 // WTSGetActiveConsoleSessionId is a very cheap API. It basically reads 132 // WTSGetActiveConsoleSessionId is a very cheap API. It basically reads
128 // a single value from shared memory. Therefore it is better to check if 133 // a single value from shared memory. Therefore it is better to check if
129 // the console session is still the same every time a session change 134 // the console session is still the same every time a session change
130 // notification event is posted. This also takes care of coalescing multiple 135 // notification event is posted. This also takes care of coalescing multiple
131 // events into one since we look at the latest state. 136 // events into one since we look at the latest state.
132 uint32 console_session_id = WTSGetActiveConsoleSessionId(); 137 uint32 console_session_id = WTSGetActiveConsoleSessionId();
133 if (console_session_id_ != console_session_id) { 138 if (console_session_id_ != console_session_id) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 run_routine_ = &HostService::RunInConsole; 194 run_routine_ = &HostService::RunInConsole;
190 } 195 }
191 196
192 return true; 197 return true;
193 } 198 }
194 199
195 int HostService::Run() { 200 int HostService::Run() {
196 return (this->*run_routine_)(); 201 return (this->*run_routine_)();
197 } 202 }
198 203
199 void HostService::RunMessageLoop(MessageLoop* message_loop) { 204 void HostService::CreateLauncher(
200 // Launch the I/O thread. 205 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
201 base::Thread io_thread(kIoThreadName);
202 base::Thread::Options io_thread_options(MessageLoop::TYPE_IO, 0);
203 if (!io_thread.StartWithOptions(io_thread_options)) {
204 LOG(ERROR) << "Failed to start the I/O thread";
205 stopped_event_.Signal();
206 return;
207 }
208 206
209 #if defined(REMOTING_MULTI_PROCESS) 207 #if defined(REMOTING_MULTI_PROCESS)
210 208
211 child_ = DaemonProcess::Create( 209 child_ = DaemonProcess::Create(
212 main_task_runner_, 210 main_task_runner_,
213 io_thread.message_loop_proxy(), 211 io_task_runner,
214 base::Bind(&HostService::OnChildStopped, 212 base::Bind(&HostService::OnChildStopped,
215 base::Unretained(this))).PassAs<Stoppable>(); 213 base::Unretained(this))).PassAs<Stoppable>();
216 214
217 #else // !defined(REMOTING_MULTI_PROCESS) 215 #else // !defined(REMOTING_MULTI_PROCESS)
218 216
219 // Create the session process launcher. 217 // Create the session process launcher.
220 child_.reset(new WtsSessionProcessLauncher( 218 child_.reset(new WtsSessionProcessLauncher(
221 base::Bind(&HostService::OnChildStopped, base::Unretained(this)), 219 base::Bind(&HostService::OnChildStopped, base::Unretained(this)),
222 this, 220 this,
223 main_task_runner_, 221 main_task_runner_,
224 io_thread.message_loop_proxy())); 222 io_task_runner));
225 223
226 #endif // !defined(REMOTING_MULTI_PROCESS) 224 #endif // !defined(REMOTING_MULTI_PROCESS)
225 }
226
227 void HostService::RunMessageLoop(MessageLoop* message_loop) {
228 // Launch the I/O thread.
229 base::Thread io_thread(kIoThreadName);
230 base::Thread::Options io_thread_options(MessageLoop::TYPE_IO, 0);
231 if (!io_thread.StartWithOptions(io_thread_options)) {
232 LOG(FATAL) << "Failed to start the I/O thread";
233 return;
234 }
235
236 CreateLauncher(new AutoThreadTaskRunner(io_thread.message_loop_proxy(),
237 main_task_runner_));
227 238
228 // Run the service. 239 // Run the service.
229 message_loop->Run(); 240 message_loop->Run();
230
231 // Release the control handler.
232 stopped_event_.Signal();
233 } 241 }
234 242
235 int HostService::Elevate() { 243 int HostService::Elevate() {
236 // Get the name of the binary to launch. 244 // Get the name of the binary to launch.
237 FilePath binary = 245 FilePath binary =
238 CommandLine::ForCurrentProcess()->GetSwitchValuePath(kElevateSwitchName); 246 CommandLine::ForCurrentProcess()->GetSwitchValuePath(kElevateSwitchName);
239 247
240 // Create the child process command line by copying known switches from our 248 // Create the child process command line by copying known switches from our
241 // command line. 249 // command line.
242 CommandLine command_line(CommandLine::NO_PROGRAM); 250 CommandLine command_line(CommandLine::NO_PROGRAM);
(...skipping 29 matching lines...) Expand all
272 << "Failed to connect to the service control manager"; 280 << "Failed to connect to the service control manager";
273 return kErrorExitCode; 281 return kErrorExitCode;
274 } 282 }
275 283
276 return kSuccessExitCode; 284 return kSuccessExitCode;
277 } 285 }
278 286
279 int HostService::RunInConsole() { 287 int HostService::RunInConsole() {
280 MessageLoop message_loop(MessageLoop::TYPE_UI); 288 MessageLoop message_loop(MessageLoop::TYPE_UI);
281 289
282 // Allow other threads to post to our message loop. 290 // Keep a reference to the main message loop while it is used. Once the last
283 main_task_runner_ = message_loop.message_loop_proxy(); 291 // reference is dropped, QuitClosure() will be posted to the loop.
292 main_task_runner_ =
293 new AutoThreadTaskRunner(message_loop.message_loop_proxy(),
294 base::Bind(&QuitMessageLoop, &message_loop));
284 295
285 int result = kErrorExitCode; 296 int result = kErrorExitCode;
286 297
287 // Subscribe to Ctrl-C and other console events. 298 // Subscribe to Ctrl-C and other console events.
288 if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) { 299 if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) {
289 LOG_GETLASTERROR(ERROR) 300 LOG_GETLASTERROR(ERROR)
290 << "Failed to set console control handler"; 301 << "Failed to set console control handler";
291 return result; 302 return result;
292 } 303 }
293 304
(...skipping 26 matching lines...) Expand all
320 // session. 331 // session.
321 main_task_runner_->PostTask(FROM_HERE, base::Bind( 332 main_task_runner_->PostTask(FROM_HERE, base::Bind(
322 &HostService::OnSessionChange, base::Unretained(this))); 333 &HostService::OnSessionChange, base::Unretained(this)));
323 334
324 // Subscribe to session change notifications. 335 // Subscribe to session change notifications.
325 if (WTSRegisterSessionNotification(window, 336 if (WTSRegisterSessionNotification(window,
326 NOTIFY_FOR_ALL_SESSIONS) != FALSE) { 337 NOTIFY_FOR_ALL_SESSIONS) != FALSE) {
327 // Run the service. 338 // Run the service.
328 RunMessageLoop(&message_loop); 339 RunMessageLoop(&message_loop);
329 340
341 // Release the control handler.
342 stopped_event_.Signal();
343
330 WTSUnRegisterSessionNotification(window); 344 WTSUnRegisterSessionNotification(window);
331 result = kSuccessExitCode; 345 result = kSuccessExitCode;
332 } 346 }
333 347
334 cleanup: 348 cleanup:
335 if (window != NULL) { 349 if (window != NULL) {
336 DestroyWindow(window); 350 DestroyWindow(window);
337 } 351 }
338 352
339 if (atom != 0) { 353 if (atom != 0) {
(...skipping 28 matching lines...) Expand all
368 self->main_task_runner_->PostTask(FROM_HERE, base::Bind( 382 self->main_task_runner_->PostTask(FROM_HERE, base::Bind(
369 &HostService::OnSessionChange, base::Unretained(self))); 383 &HostService::OnSessionChange, base::Unretained(self)));
370 return NO_ERROR; 384 return NO_ERROR;
371 385
372 default: 386 default:
373 return ERROR_CALL_NOT_IMPLEMENTED; 387 return ERROR_CALL_NOT_IMPLEMENTED;
374 } 388 }
375 } 389 }
376 390
377 VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) { 391 VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) {
378 MessageLoop message_loop; 392 MessageLoop message_loop(MessageLoop::TYPE_DEFAULT);
379 393
380 // Allow other threads to post to our message loop. 394 // Keep a reference to the main message loop while it is used. Once the last
395 // reference is dropped QuitClosure() will be posted to the loop.
381 HostService* self = HostService::GetInstance(); 396 HostService* self = HostService::GetInstance();
382 self->main_task_runner_ = message_loop.message_loop_proxy(); 397 self->main_task_runner_ =
398 new AutoThreadTaskRunner(message_loop.message_loop_proxy(),
399 base::Bind(&QuitMessageLoop, &message_loop));
383 400
384 // Register the service control handler. 401 // Register the service control handler.
385 self->service_status_handle_ = 402 self->service_status_handle_ =
386 RegisterServiceCtrlHandlerExW(kWindowsServiceName, 403 RegisterServiceCtrlHandlerExW(kWindowsServiceName,
387 &HostService::ServiceControlHandler, 404 &HostService::ServiceControlHandler,
388 self); 405 self);
389 if (self->service_status_handle_ == 0) { 406 if (self->service_status_handle_ == 0) {
390 LOG_GETLASTERROR(ERROR) 407 LOG_GETLASTERROR(ERROR)
391 << "Failed to register the service control handler"; 408 << "Failed to register the service control handler";
392 return; 409 return;
(...skipping 16 matching lines...) Expand all
409 } 426 }
410 427
411 // Post a dummy session change notification to peek up the current console 428 // Post a dummy session change notification to peek up the current console
412 // session. 429 // session.
413 self->main_task_runner_->PostTask(FROM_HERE, base::Bind( 430 self->main_task_runner_->PostTask(FROM_HERE, base::Bind(
414 &HostService::OnSessionChange, base::Unretained(self))); 431 &HostService::OnSessionChange, base::Unretained(self)));
415 432
416 // Run the service. 433 // Run the service.
417 self->RunMessageLoop(&message_loop); 434 self->RunMessageLoop(&message_loop);
418 435
436 // Release the control handler.
437 self->stopped_event_.Signal();
438
419 // Tell SCM that the service is stopped. 439 // Tell SCM that the service is stopped.
420 service_status.dwCurrentState = SERVICE_STOPPED; 440 service_status.dwCurrentState = SERVICE_STOPPED;
421 service_status.dwControlsAccepted = 0; 441 service_status.dwControlsAccepted = 0;
422 442
423 if (!SetServiceStatus(self->service_status_handle_, &service_status)) { 443 if (!SetServiceStatus(self->service_status_handle_, &service_status)) {
424 LOG_GETLASTERROR(ERROR) 444 LOG_GETLASTERROR(ERROR)
425 << "Failed to report service status to the service control manager"; 445 << "Failed to report service status to the service control manager";
426 return; 446 return;
427 } 447 }
428 } 448 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 } 500 }
481 501
482 remoting::HostService* service = remoting::HostService::GetInstance(); 502 remoting::HostService* service = remoting::HostService::GetInstance();
483 if (!service->InitWithCommandLine(command_line)) { 503 if (!service->InitWithCommandLine(command_line)) {
484 usage(command_line->GetProgram()); 504 usage(command_line->GetProgram());
485 return kUsageExitCode; 505 return kUsageExitCode;
486 } 506 }
487 507
488 return service->Run(); 508 return service->Run();
489 } 509 }
OLDNEW
« no previous file with comments | « remoting/host/win/host_service.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698