Chromium Code Reviews| OLD | NEW | 
|---|---|
| 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_message_loop.h" | |
| 28 #include "remoting/base/auto_thread.h" | |
| 27 #include "remoting/base/breakpad.h" | 29 #include "remoting/base/breakpad.h" | 
| 28 #include "remoting/base/scoped_sc_handle_win.h" | 30 #include "remoting/base/scoped_sc_handle_win.h" | 
| 29 #include "remoting/base/stoppable.h" | 31 #include "remoting/base/stoppable.h" | 
| 30 #include "remoting/host/branding.h" | 32 #include "remoting/host/branding.h" | 
| 31 | 33 | 
| 32 #if defined(REMOTING_MULTI_PROCESS) | 34 #if defined(REMOTING_MULTI_PROCESS) | 
| 33 #include "remoting/host/daemon_process.h" | 35 #include "remoting/host/daemon_process.h" | 
| 34 #endif // defined(REMOTING_MULTI_PROCESS) | 36 #endif // defined(REMOTING_MULTI_PROCESS) | 
| 35 | 37 | 
| 36 #include "remoting/host/usage_stats_consent.h" | 38 #include "remoting/host/usage_stats_consent.h" | 
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 113 } | 115 } | 
| 114 | 116 | 
| 115 void HostService::RemoveWtsConsoleObserver(WtsConsoleObserver* observer) { | 117 void HostService::RemoveWtsConsoleObserver(WtsConsoleObserver* observer) { | 
| 116 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 118 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 
| 117 | 119 | 
| 118 console_observers_.RemoveObserver(observer); | 120 console_observers_.RemoveObserver(observer); | 
| 119 } | 121 } | 
| 120 | 122 | 
| 121 void HostService::OnChildStopped() { | 123 void HostService::OnChildStopped() { | 
| 122 child_.reset(NULL); | 124 child_.reset(NULL); | 
| 123 main_task_runner_->PostTask(FROM_HERE, MessageLoop::QuitClosure()); | 125 main_task_runner_ = NULL; | 
| 124 } | 126 } | 
| 125 | 127 | 
| 126 void HostService::OnSessionChange() { | 128 void HostService::OnSessionChange() { | 
| 127 // WTSGetActiveConsoleSessionId is a very cheap API. It basically reads | 129 // WTSGetActiveConsoleSessionId is a very cheap API. It basically reads | 
| 128 // a single value from shared memory. Therefore it is better to check if | 130 // 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 | 131 // the console session is still the same every time a session change | 
| 130 // notification event is posted. This also takes care of coalescing multiple | 132 // notification event is posted. This also takes care of coalescing multiple | 
| 131 // events into one since we look at the latest state. | 133 // events into one since we look at the latest state. | 
| 132 uint32 console_session_id = WTSGetActiveConsoleSessionId(); | 134 uint32 console_session_id = WTSGetActiveConsoleSessionId(); | 
| 133 if (console_session_id_ != console_session_id) { | 135 if (console_session_id_ != console_session_id) { | 
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 189 run_routine_ = &HostService::RunInConsole; | 191 run_routine_ = &HostService::RunInConsole; | 
| 190 } | 192 } | 
| 191 | 193 | 
| 192 return true; | 194 return true; | 
| 193 } | 195 } | 
| 194 | 196 | 
| 195 int HostService::Run() { | 197 int HostService::Run() { | 
| 196 return (this->*run_routine_)(); | 198 return (this->*run_routine_)(); | 
| 197 } | 199 } | 
| 198 | 200 | 
| 199 void HostService::RunMessageLoop(MessageLoop* message_loop) { | 201 bool HostService::BeforeMessageLoop() { | 
| 200 // Launch the I/O thread. | 202 // Launch the I/O thread. | 
| 201 base::Thread io_thread(kIoThreadName); | 203 scoped_refptr<AutoThread> io_thread( | 
| 204 new AutoThread(kIoThreadName, main_task_runner_)); | |
| 
 
Wez
2012/08/24 21:30:49
Can you instead create a normal Thread in RunMessa
 
alexeypa (please no reviews)
2012/08/27 21:19:40
Done.
 
 | |
| 202 base::Thread::Options io_thread_options(MessageLoop::TYPE_IO, 0); | 205 base::Thread::Options io_thread_options(MessageLoop::TYPE_IO, 0); | 
| 203 if (!io_thread.StartWithOptions(io_thread_options)) { | 206 if (!io_thread->StartWithOptions(io_thread_options)) { | 
| 204 LOG(ERROR) << "Failed to start the I/O thread"; | 207 LOG(FATAL) << "Failed to start the I/O thread"; | 
| 205 stopped_event_.Signal(); | 208 return false; | 
| 206 return; | |
| 207 } | 209 } | 
| 208 | 210 | 
| 209 #if defined(REMOTING_MULTI_PROCESS) | 211 #if defined(REMOTING_MULTI_PROCESS) | 
| 210 | 212 | 
| 211 child_ = DaemonProcess::Create( | 213 child_ = DaemonProcess::Create( | 
| 212 main_task_runner_, | 214 main_task_runner_, | 
| 213 io_thread.message_loop_proxy(), | 215 io_thread, | 
| 214 base::Bind(&HostService::OnChildStopped, | 216 base::Bind(&HostService::OnChildStopped, | 
| 215 base::Unretained(this))).PassAs<Stoppable>(); | 217 base::Unretained(this))).PassAs<Stoppable>(); | 
| 216 | 218 | 
| 217 #else // !defined(REMOTING_MULTI_PROCESS) | 219 #else // !defined(REMOTING_MULTI_PROCESS) | 
| 218 | 220 | 
| 219 // Create the session process launcher. | 221 // Create the session process launcher. | 
| 220 child_.reset(new WtsSessionProcessLauncher( | 222 child_.reset(new WtsSessionProcessLauncher( | 
| 221 base::Bind(&HostService::OnChildStopped, base::Unretained(this)), | 223 base::Bind(&HostService::OnChildStopped, base::Unretained(this)), | 
| 222 this, | 224 this, | 
| 223 main_task_runner_, | 225 main_task_runner_, | 
| 224 io_thread.message_loop_proxy())); | 226 io_thread)); | 
| 225 | 227 | 
| 226 #endif // !defined(REMOTING_MULTI_PROCESS) | 228 #endif // !defined(REMOTING_MULTI_PROCESS) | 
| 227 | 229 | 
| 230 return true; | |
| 231 } | |
| 232 | |
| 233 void HostService::RunMessageLoop(MessageLoop* message_loop) { | |
| 228 // Run the service. | 234 // Run the service. | 
| 229 message_loop->Run(); | 235 if (BeforeMessageLoop()) { | 
| 236 message_loop->Run(); | |
| 237 } | |
| 230 | 238 | 
| 231 // Release the control handler. | 239 // Release the control handler. | 
| 232 stopped_event_.Signal(); | 240 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 | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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_ = new AutoMessageLoop(&message_loop); | |
| 284 | 293 | 
| 285 int result = kErrorExitCode; | 294 int result = kErrorExitCode; | 
| 286 | 295 | 
| 287 // Subscribe to Ctrl-C and other console events. | 296 // Subscribe to Ctrl-C and other console events. | 
| 288 if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) { | 297 if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) { | 
| 289 LOG_GETLASTERROR(ERROR) | 298 LOG_GETLASTERROR(ERROR) | 
| 290 << "Failed to set console control handler"; | 299 << "Failed to set console control handler"; | 
| 291 return result; | 300 return result; | 
| 292 } | 301 } | 
| 293 | 302 | 
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 368 self->main_task_runner_->PostTask(FROM_HERE, base::Bind( | 377 self->main_task_runner_->PostTask(FROM_HERE, base::Bind( | 
| 369 &HostService::OnSessionChange, base::Unretained(self))); | 378 &HostService::OnSessionChange, base::Unretained(self))); | 
| 370 return NO_ERROR; | 379 return NO_ERROR; | 
| 371 | 380 | 
| 372 default: | 381 default: | 
| 373 return ERROR_CALL_NOT_IMPLEMENTED; | 382 return ERROR_CALL_NOT_IMPLEMENTED; | 
| 374 } | 383 } | 
| 375 } | 384 } | 
| 376 | 385 | 
| 377 VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) { | 386 VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) { | 
| 378 MessageLoop message_loop; | 387 MessageLoop message_loop(MessageLoop::TYPE_DEFAULT); | 
| 379 | 388 | 
| 380 // Allow other threads to post to our message loop. | 389 // Keep a reference to the main message loop while it is used. Once the last | 
| 390 // reference is dropped QuitClosure() will be posted to the loop. | |
| 381 HostService* self = HostService::GetInstance(); | 391 HostService* self = HostService::GetInstance(); | 
| 382 self->main_task_runner_ = message_loop.message_loop_proxy(); | 392 self->main_task_runner_ = new AutoMessageLoop(&message_loop); | 
| 383 | 393 | 
| 384 // Register the service control handler. | 394 // Register the service control handler. | 
| 385 self->service_status_handle_ = | 395 self->service_status_handle_ = | 
| 386 RegisterServiceCtrlHandlerExW(kWindowsServiceName, | 396 RegisterServiceCtrlHandlerExW(kWindowsServiceName, | 
| 387 &HostService::ServiceControlHandler, | 397 &HostService::ServiceControlHandler, | 
| 388 self); | 398 self); | 
| 389 if (self->service_status_handle_ == 0) { | 399 if (self->service_status_handle_ == 0) { | 
| 390 LOG_GETLASTERROR(ERROR) | 400 LOG_GETLASTERROR(ERROR) | 
| 391 << "Failed to register the service control handler"; | 401 << "Failed to register the service control handler"; | 
| 392 return; | 402 return; | 
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 480 } | 490 } | 
| 481 | 491 | 
| 482 remoting::HostService* service = remoting::HostService::GetInstance(); | 492 remoting::HostService* service = remoting::HostService::GetInstance(); | 
| 483 if (!service->InitWithCommandLine(command_line)) { | 493 if (!service->InitWithCommandLine(command_line)) { | 
| 484 usage(command_line->GetProgram()); | 494 usage(command_line->GetProgram()); | 
| 485 return kUsageExitCode; | 495 return kUsageExitCode; | 
| 486 } | 496 } | 
| 487 | 497 | 
| 488 return service->Run(); | 498 return service->Run(); | 
| 489 } | 499 } | 
| OLD | NEW |