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

Side by Side Diff: remoting/host/host_service_win.cc

Issue 10796099: Introducing remoting::Stoppable helper base class implementing asynchronous shutdown on a specific t (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 5 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/host_service_win.h" 8 #include "remoting/host/host_service_win.h"
9 9
10 #include <windows.h> 10 #include <windows.h>
11 #include <wtsapi32.h> 11 #include <wtsapi32.h>
12 #include <stdio.h> 12 #include <stdio.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/bind.h" 16 #include "base/bind.h"
17 #include "base/command_line.h" 17 #include "base/command_line.h"
18 #include "base/file_util.h" 18 #include "base/file_util.h"
19 #include "base/logging.h" 19 #include "base/logging.h"
20 #include "base/message_loop.h" 20 #include "base/message_loop.h"
21 #include "base/path_service.h" 21 #include "base/path_service.h"
22 #include "base/stringprintf.h" 22 #include "base/stringprintf.h"
23 #include "base/threading/thread.h" 23 #include "base/threading/thread.h"
24 #include "base/utf_string_conversions.h" 24 #include "base/utf_string_conversions.h"
25 #include "base/win/wrapped_window_proc.h" 25 #include "base/win/wrapped_window_proc.h"
26 #include "remoting/base/auto_message_loop.h"
27 #include "remoting/base/auto_thread.h"
26 #include "remoting/base/breakpad.h" 28 #include "remoting/base/breakpad.h"
27 #include "remoting/base/scoped_sc_handle_win.h" 29 #include "remoting/base/scoped_sc_handle_win.h"
30 #include "remoting/base/shutdownable.h"
28 #include "remoting/host/branding.h" 31 #include "remoting/host/branding.h"
29 #include "remoting/host/host_service_resource.h" 32 #include "remoting/host/host_service_resource.h"
30 #include "remoting/host/usage_stats_consent.h" 33 #include "remoting/host/usage_stats_consent.h"
31 #include "remoting/host/wts_console_observer_win.h" 34 #include "remoting/host/wts_console_observer_win.h"
32 #include "remoting/host/wts_session_process_launcher_win.h" 35 #include "remoting/host/wts_session_process_launcher_win.h"
33 36
34 using base::StringPrintf; 37 using base::StringPrintf;
35 38
36 namespace { 39 namespace {
37 40
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 void usage(const char* program_name) { 78 void usage(const char* program_name) {
76 fprintf(stderr, kUsageMessage, program_name); 79 fprintf(stderr, kUsageMessage, program_name);
77 } 80 }
78 81
79 } // namespace 82 } // namespace
80 83
81 namespace remoting { 84 namespace remoting {
82 85
83 HostService::HostService() : 86 HostService::HostService() :
84 console_session_id_(kInvalidSessionId), 87 console_session_id_(kInvalidSessionId),
85 message_loop_(NULL),
86 run_routine_(&HostService::RunAsService), 88 run_routine_(&HostService::RunAsService),
87 service_name_(kWindowsServiceName), 89 service_name_(kWindowsServiceName),
88 service_status_handle_(0), 90 service_status_handle_(0),
89 shutting_down_(false),
90 stopped_event_(true, false) { 91 stopped_event_(true, false) {
91 } 92 }
92 93
93 HostService::~HostService() { 94 HostService::~HostService() {
94 } 95 }
95 96
96 void HostService::AddWtsConsoleObserver(WtsConsoleObserver* observer) { 97 void HostService::AddWtsConsoleObserver(WtsConsoleObserver* observer) {
97 DCHECK(message_loop_->message_loop_proxy()->BelongsToCurrentThread()); 98 DCHECK(message_loop_->BelongsToCurrentThread());
98 99
99 console_observers_.AddObserver(observer); 100 console_observers_.AddObserver(observer);
100 } 101 }
101 102
102 void HostService::RemoveWtsConsoleObserver(WtsConsoleObserver* observer) { 103 void HostService::RemoveWtsConsoleObserver(WtsConsoleObserver* observer) {
103 DCHECK(message_loop_->message_loop_proxy()->BelongsToCurrentThread()); 104 DCHECK(message_loop_->BelongsToCurrentThread());
104 105
105 console_observers_.RemoveObserver(observer); 106 console_observers_.RemoveObserver(observer);
107 }
106 108
107 // Stop the service if there are no more observers. 109 void HostService::OnLauncherShutdown(Shutdownable* /* launcher */) {
108 if (!console_observers_.might_have_observers()) { 110 launcher_.reset(NULL);
109 message_loop_->PostTask(FROM_HERE, MessageLoop::QuitClosure()); 111 message_loop_ = NULL;
110 }
111 } 112 }
112 113
113 void HostService::OnSessionChange() { 114 void HostService::OnSessionChange() {
114 // WTSGetActiveConsoleSessionId is a very cheap API. It basically reads 115 // WTSGetActiveConsoleSessionId is a very cheap API. It basically reads
115 // a single value from shared memory. Therefore it is better to check if 116 // a single value from shared memory. Therefore it is better to check if
116 // the console session is still the same every time a session change 117 // the console session is still the same every time a session change
117 // notification event is posted. This also takes care of coalescing multiple 118 // notification event is posted. This also takes care of coalescing multiple
118 // events into one since we look at the latest state. 119 // events into one since we look at the latest state.
119 uint32 console_session_id = kInvalidSessionId; 120 uint32 console_session_id = WTSGetActiveConsoleSessionId();
120 if (!shutting_down_) {
121 console_session_id = WTSGetActiveConsoleSessionId();
122 }
123 if (console_session_id_ != console_session_id) { 121 if (console_session_id_ != console_session_id) {
124 if (console_session_id_ != kInvalidSessionId) { 122 if (console_session_id_ != kInvalidSessionId) {
125 FOR_EACH_OBSERVER(WtsConsoleObserver, 123 FOR_EACH_OBSERVER(WtsConsoleObserver,
126 console_observers_, 124 console_observers_,
127 OnSessionDetached()); 125 OnSessionDetached());
128 } 126 }
129 127
130 console_session_id_ = console_session_id; 128 console_session_id_ = console_session_id;
131 129
132 if (console_session_id_ != kInvalidSessionId) { 130 if (console_session_id_ != kInvalidSessionId) {
133 FOR_EACH_OBSERVER(WtsConsoleObserver, 131 FOR_EACH_OBSERVER(WtsConsoleObserver,
134 console_observers_, 132 console_observers_,
135 OnSessionAttached(console_session_id_)); 133 OnSessionAttached(console_session_id_));
136 } 134 }
137 } 135 }
138 } 136 }
139 137
140 BOOL WINAPI HostService::ConsoleControlHandler(DWORD event) { 138 BOOL WINAPI HostService::ConsoleControlHandler(DWORD event) {
141 HostService* self = HostService::GetInstance(); 139 HostService* self = HostService::GetInstance();
142 switch (event) { 140 switch (event) {
143 case CTRL_C_EVENT: 141 case CTRL_C_EVENT:
144 case CTRL_BREAK_EVENT: 142 case CTRL_BREAK_EVENT:
145 case CTRL_CLOSE_EVENT: 143 case CTRL_CLOSE_EVENT:
146 case CTRL_LOGOFF_EVENT: 144 case CTRL_LOGOFF_EVENT:
147 case CTRL_SHUTDOWN_EVENT: 145 case CTRL_SHUTDOWN_EVENT:
148 self->message_loop_->PostTask(FROM_HERE, MessageLoop::QuitClosure()); 146 self->message_loop_->PostTask(FROM_HERE, base::Bind(
147 &WtsSessionProcessLauncher::Shutdown,
148 base::Unretained(self->launcher_.get())));
149 self->stopped_event_.Wait(); 149 self->stopped_event_.Wait();
150 return TRUE; 150 return TRUE;
151 151
152 default: 152 default:
153 return FALSE; 153 return FALSE;
154 } 154 }
155 } 155 }
156 156
157 HostService* HostService::GetInstance() { 157 HostService* HostService::GetInstance() {
158 return Singleton<HostService>::get(); 158 return Singleton<HostService>::get();
(...skipping 29 matching lines...) Expand all
188 run_routine_ = &HostService::RunInConsole; 188 run_routine_ = &HostService::RunInConsole;
189 } 189 }
190 190
191 return true; 191 return true;
192 } 192 }
193 193
194 int HostService::Run() { 194 int HostService::Run() {
195 return (this->*run_routine_)(); 195 return (this->*run_routine_)();
196 } 196 }
197 197
198 void HostService::RunMessageLoop() { 198 bool HostService::BeforeMessageLoop() {
199 // Launch the I/O thread. 199 // Launch the I/O thread.
200 base::Thread io_thread(kIoThreadName); 200 scoped_refptr<AutoThread> io_thread(
201 new AutoThread(kIoThreadName, message_loop_));
Sergey Ulanov 2012/07/23 22:44:37 Why do we need thread to be refcounted? Can we us
alexeypa (please no reviews) 2012/07/23 23:44:53 To make sure it is alive until all objects dependi
202
201 base::Thread::Options io_thread_options(MessageLoop::TYPE_IO, 0); 203 base::Thread::Options io_thread_options(MessageLoop::TYPE_IO, 0);
202 if (!io_thread.StartWithOptions(io_thread_options)) { 204 if (!io_thread->StartWithOptions(io_thread_options)) {
203 LOG(FATAL) << "Failed to start the I/O thread"; 205 LOG(FATAL) << "Failed to start the I/O thread";
204 shutting_down_ = true; 206 return false;
205 stopped_event_.Signal();
206 return;
207 } 207 }
208 208
209 WtsSessionProcessLauncher launcher(this, host_binary_, 209 // Create the session process launcher.
210 message_loop_->message_loop_proxy(), 210 launcher_.reset(new WtsSessionProcessLauncher(
211 io_thread.message_loop_proxy()); 211 base::Bind(&HostService::OnLauncherShutdown, base::Unretained(this)),
212 212 this,
213 host_binary_,
214 message_loop_,
215 io_thread));
216 return true;
217 }
218 void HostService::RunMessageLoop() {
213 // Run the service. 219 // Run the service.
214 message_loop_->Run(); 220 if (BeforeMessageLoop()) {
215 221 message_loop_->Run();
216 // Clean up the observers by emulating detaching from the console. 222 }
217 shutting_down_ = true;
218 OnSessionChange();
219 223
220 // Release the control handler. 224 // Release the control handler.
221 stopped_event_.Signal(); 225 stopped_event_.Signal();
222 } 226 }
223 227
224 int HostService::RunAsService() { 228 int HostService::RunAsService() {
225 SERVICE_TABLE_ENTRYW dispatch_table[] = { 229 SERVICE_TABLE_ENTRYW dispatch_table[] = {
226 { const_cast<LPWSTR>(service_name_.c_str()), &HostService::ServiceMain }, 230 { const_cast<LPWSTR>(service_name_.c_str()), &HostService::ServiceMain },
227 { NULL, NULL } 231 { NULL, NULL }
228 }; 232 };
229 233
230 if (!StartServiceCtrlDispatcherW(dispatch_table)) { 234 if (!StartServiceCtrlDispatcherW(dispatch_table)) {
231 LOG_GETLASTERROR(ERROR) 235 LOG_GETLASTERROR(ERROR)
232 << "Failed to connect to the service control manager"; 236 << "Failed to connect to the service control manager";
233 return kErrorExitCode; 237 return kErrorExitCode;
234 } 238 }
235 239
236 return kSuccessExitCode; 240 return kSuccessExitCode;
237 } 241 }
238 242
239 int HostService::RunInConsole() { 243 int HostService::RunInConsole() {
240 MessageLoop message_loop(MessageLoop::TYPE_UI); 244 AutoMessageLoop message_loop(MessageLoop::TYPE_UI);
Sergey Ulanov 2012/07/23 22:44:37 You are creating ref-counted object on stack. That
alexeypa (please no reviews) 2012/07/23 23:44:53 I control the destruction logic for this object. A
241 245
242 // Allow other threads to post to our message loop. 246 // Allow other threads to post to our message loop.
243 message_loop_ = &message_loop; 247 message_loop_ = scoped_refptr<AutoMessageLoop>(&message_loop);
244 248
245 int result = kErrorExitCode; 249 int result = kErrorExitCode;
246 250
247 // Subscribe to Ctrl-C and other console events. 251 // Subscribe to Ctrl-C and other console events.
248 if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) { 252 if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) {
249 LOG_GETLASTERROR(ERROR) 253 LOG_GETLASTERROR(ERROR)
250 << "Failed to set console control handler"; 254 << "Failed to set console control handler";
251 return result; 255 return result;
252 } 256 }
253 257
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 } 301 }
298 302
299 if (atom != 0) { 303 if (atom != 0) {
300 UnregisterClass(MAKEINTATOM(atom), instance); 304 UnregisterClass(MAKEINTATOM(atom), instance);
301 } 305 }
302 306
303 // Unsubscribe from console events. Ignore the exit code. There is nothing 307 // Unsubscribe from console events. Ignore the exit code. There is nothing
304 // we can do about it now and the program is about to exit anyway. Even if 308 // we can do about it now and the program is about to exit anyway. Even if
305 // it crashes nothing is going to be broken because of it. 309 // it crashes nothing is going to be broken because of it.
306 SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, FALSE); 310 SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, FALSE);
307
308 message_loop_ = NULL;
309 return result; 311 return result;
310 } 312 }
311 313
312 DWORD WINAPI HostService::ServiceControlHandler(DWORD control, 314 DWORD WINAPI HostService::ServiceControlHandler(DWORD control,
313 DWORD event_type, 315 DWORD event_type,
314 LPVOID event_data, 316 LPVOID event_data,
315 LPVOID context) { 317 LPVOID context) {
316 HostService* self = reinterpret_cast<HostService*>(context); 318 HostService* self = reinterpret_cast<HostService*>(context);
317 switch (control) { 319 switch (control) {
318 case SERVICE_CONTROL_INTERROGATE: 320 case SERVICE_CONTROL_INTERROGATE:
319 return NO_ERROR; 321 return NO_ERROR;
320 322
321 case SERVICE_CONTROL_SHUTDOWN: 323 case SERVICE_CONTROL_SHUTDOWN:
322 case SERVICE_CONTROL_STOP: 324 case SERVICE_CONTROL_STOP:
323 self->message_loop_->PostTask(FROM_HERE, MessageLoop::QuitClosure()); 325 self->message_loop_->PostTask(FROM_HERE, base::Bind(
326 &WtsSessionProcessLauncher::Shutdown,
327 base::Unretained(self->launcher_.get())));
324 self->stopped_event_.Wait(); 328 self->stopped_event_.Wait();
325 return NO_ERROR; 329 return NO_ERROR;
326 330
327 case SERVICE_CONTROL_SESSIONCHANGE: 331 case SERVICE_CONTROL_SESSIONCHANGE:
328 self->message_loop_->PostTask(FROM_HERE, base::Bind( 332 self->message_loop_->PostTask(FROM_HERE, base::Bind(
329 &HostService::OnSessionChange, base::Unretained(self))); 333 &HostService::OnSessionChange, base::Unretained(self)));
330 return NO_ERROR; 334 return NO_ERROR;
331 335
332 default: 336 default:
333 return ERROR_CALL_NOT_IMPLEMENTED; 337 return ERROR_CALL_NOT_IMPLEMENTED;
334 } 338 }
335 } 339 }
336 340
337 VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) { 341 VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) {
338 MessageLoop message_loop; 342 AutoMessageLoop message_loop(MessageLoop::TYPE_DEFAULT);
Sergey Ulanov 2012/07/23 22:44:37 Why do we need MessageLoop to be refcounted here?
alexeypa (please no reviews) 2012/07/23 23:44:53 It doe snot have to outlive ServiceMain(). It is r
339 343
340 // Allow other threads to post to our message loop. 344 // Allow other threads to post to our message loop.
341 HostService* self = HostService::GetInstance(); 345 HostService* self = HostService::GetInstance();
342 self->message_loop_ = &message_loop; 346 self->message_loop_ = scoped_refptr<AutoMessageLoop>(&message_loop);
343 347
344 // Register the service control handler. 348 // Register the service control handler.
345 self->service_status_handle_ = 349 self->service_status_handle_ =
346 RegisterServiceCtrlHandlerExW(self->service_name_.c_str(), 350 RegisterServiceCtrlHandlerExW(self->service_name_.c_str(),
347 &HostService::ServiceControlHandler, 351 &HostService::ServiceControlHandler,
348 self); 352 self);
349 if (self->service_status_handle_ == 0) { 353 if (self->service_status_handle_ == 0) {
350 LOG_GETLASTERROR(ERROR) 354 LOG_GETLASTERROR(ERROR)
351 << "Failed to register the service control handler"; 355 << "Failed to register the service control handler";
352 return; 356 return;
(...skipping 25 matching lines...) Expand all
378 382
379 // Tell SCM that the service is stopped. 383 // Tell SCM that the service is stopped.
380 service_status.dwCurrentState = SERVICE_STOPPED; 384 service_status.dwCurrentState = SERVICE_STOPPED;
381 service_status.dwControlsAccepted = 0; 385 service_status.dwControlsAccepted = 0;
382 386
383 if (!SetServiceStatus(self->service_status_handle_, &service_status)) { 387 if (!SetServiceStatus(self->service_status_handle_, &service_status)) {
384 LOG_GETLASTERROR(ERROR) 388 LOG_GETLASTERROR(ERROR)
385 << "Failed to report service status to the service control manager"; 389 << "Failed to report service status to the service control manager";
386 return; 390 return;
387 } 391 }
388
389 self->message_loop_ = NULL;
390 } 392 }
391 393
392 LRESULT CALLBACK HostService::SessionChangeNotificationProc(HWND hwnd, 394 LRESULT CALLBACK HostService::SessionChangeNotificationProc(HWND hwnd,
393 UINT message, 395 UINT message,
394 WPARAM wparam, 396 WPARAM wparam,
395 LPARAM lparam) { 397 LPARAM lparam) {
396 switch (message) { 398 switch (message) {
397 case WM_WTSSESSION_CHANGE: { 399 case WM_WTSSESSION_CHANGE: {
398 HostService* self = HostService::GetInstance(); 400 HostService* self = HostService::GetInstance();
399 self->OnSessionChange(); 401 self->OnSessionChange();
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 } 440 }
439 441
440 remoting::HostService* service = remoting::HostService::GetInstance(); 442 remoting::HostService* service = remoting::HostService::GetInstance();
441 if (!service->InitWithCommandLine(command_line)) { 443 if (!service->InitWithCommandLine(command_line)) {
442 usage(argv[0]); 444 usage(argv[0]);
443 return kUsageExitCode; 445 return kUsageExitCode;
444 } 446 }
445 447
446 return service->Run(); 448 return service->Run();
447 } 449 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698