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/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/stringize_macros.h" |
22 #include "base/stringprintf.h" | 23 #include "base/stringprintf.h" |
23 #include "base/threading/thread.h" | 24 #include "base/threading/thread.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 | 26 |
27 #include "remoting/base/scoped_sc_handle_win.h" | 27 #include "remoting/base/scoped_sc_handle_win.h" |
28 #include "remoting/host/branding.h" | 28 #include "remoting/host/branding.h" |
29 #include "remoting/host/host_service_resource.h" | 29 #include "remoting/host/host_service_resource.h" |
30 #include "remoting/host/wts_console_observer_win.h" | 30 #include "remoting/host/wts_console_observer_win.h" |
31 #include "remoting/host/wts_session_process_launcher_win.h" | 31 #include "remoting/host/wts_session_process_launcher_win.h" |
32 | 32 |
33 using base::StringPrintf; | 33 using base::StringPrintf; |
34 | 34 |
35 namespace { | 35 namespace { |
36 | 36 |
37 // TODO(alexeypa): investigate and migrate this over to Chrome's i18n framework. | 37 // TODO(alexeypa): investigate and migrate this over to Chrome's i18n framework. |
38 const char kMuiStringFormat[] = "@%ls,-%d"; | 38 const char16 kMuiStringFormat[] = TO_L_STRING("@%ls,-%d"); |
39 const char kServiceDependencies[] = ""; | 39 const char16 kServiceDependencies[] = TO_L_STRING(""); |
40 | 40 |
41 const char kServiceCommandLineFormat[] = "\"%ls\" --host-binary=\"%ls\""; | 41 const char16 kServiceCommandLineFormat[] = |
| 42 TO_L_STRING("\"%ls\" --host-binary=\"%ls\""); |
42 | 43 |
43 const DWORD kServiceStopTimeoutMs = 30 * 1000; | 44 const DWORD kServiceStopTimeoutMs = 30 * 1000; |
44 | 45 |
45 // Session id that does not represent any session. | 46 // Session id that does not represent any session. |
46 const uint32 kInvalidSession = 0xffffffff; | 47 const uint32 kInvalidSession = 0xffffffff; |
47 | 48 |
48 const char kIoThreadName[] = "I/O thread"; | 49 const char kIoThreadName[] = "I/O thread"; |
49 | 50 |
50 // A window class for the session change notifications window. | 51 // A window class for the session change notifications window. |
51 static const char kSessionNotificationWindowClass[] = | 52 const char16 kSessionNotificationWindowClass[] = |
52 "Chromoting_SessionNotificationWindow"; | 53 TO_L_STRING("Chromoting_SessionNotificationWindow"); |
53 | 54 |
54 // Command line actions and switches: | 55 // Command line actions and switches: |
55 // "run" sumply runs the service as usual. | 56 // "run" sumply runs the service as usual. |
56 const char kRunActionName[] = "run"; | 57 const char16 kRunActionName[] = TO_L_STRING("run"); |
57 | 58 |
58 // "install" requests the service to be installed. | 59 // "install" requests the service to be installed. |
59 const char kInstallActionName[] = "install"; | 60 const char16 kInstallActionName[] = TO_L_STRING("install"); |
60 | 61 |
61 // "remove" uninstalls the service. | 62 // "remove" uninstalls the service. |
62 const char kRemoveActionName[] = "remove"; | 63 const char16 kRemoveActionName[] = TO_L_STRING("remove"); |
63 | 64 |
64 // "--console" runs the service interactively for debugging purposes. | 65 // "--console" runs the service interactively for debugging purposes. |
65 const char kConsoleSwitchName[] = "console"; | 66 const char kConsoleSwitchName[] = "console"; |
66 | 67 |
67 // "--host-binary" specifies the host binary to run in console session. | 68 // "--host-binary" specifies the host binary to run in console session. |
68 const char kHostBinarySwitchName[] = "host-binary"; | 69 const char kHostBinarySwitchName[] = "host-binary"; |
69 | 70 |
70 // "--help" or "--?" prints the usage message. | 71 // "--help" or "--?" prints the usage message. |
71 const char kHelpSwitchName[] = "help"; | 72 const char kHelpSwitchName[] = "help"; |
72 const char kQuestionSwitchName[] = "?"; | 73 const char kQuestionSwitchName[] = "?"; |
(...skipping 22 matching lines...) Expand all Loading... |
95 } | 96 } |
96 | 97 |
97 } // namespace | 98 } // namespace |
98 | 99 |
99 namespace remoting { | 100 namespace remoting { |
100 | 101 |
101 HostService::HostService() : | 102 HostService::HostService() : |
102 console_session_id_(kInvalidSession), | 103 console_session_id_(kInvalidSession), |
103 message_loop_(NULL), | 104 message_loop_(NULL), |
104 run_routine_(&HostService::RunAsService), | 105 run_routine_(&HostService::RunAsService), |
105 service_name_(UTF8ToUTF16(kWindowsServiceName)), | 106 service_name_(kWindowsServiceName), |
106 service_status_handle_(0), | 107 service_status_handle_(0), |
107 shutting_down_(false), | 108 shutting_down_(false), |
108 stopped_event_(true, false) { | 109 stopped_event_(true, false) { |
109 } | 110 } |
110 | 111 |
111 HostService::~HostService() { | 112 HostService::~HostService() { |
112 } | 113 } |
113 | 114 |
114 void HostService::AddWtsConsoleObserver(WtsConsoleObserver* observer) { | 115 void HostService::AddWtsConsoleObserver(WtsConsoleObserver* observer) { |
115 DCHECK(message_loop_->message_loop_proxy()->BelongsToCurrentThread()); | 116 DCHECK(message_loop_->message_loop_proxy()->BelongsToCurrentThread()); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 bool HostService::InitWithCommandLine(const CommandLine* command_line) { | 180 bool HostService::InitWithCommandLine(const CommandLine* command_line) { |
180 CommandLine::StringVector args = command_line->GetArgs(); | 181 CommandLine::StringVector args = command_line->GetArgs(); |
181 | 182 |
182 // Choose the action to perform. | 183 // Choose the action to perform. |
183 bool host_binary_required = true; | 184 bool host_binary_required = true; |
184 if (!args.empty()) { | 185 if (!args.empty()) { |
185 if (args.size() > 1) { | 186 if (args.size() > 1) { |
186 LOG(ERROR) << "Invalid command line: more than one action requested."; | 187 LOG(ERROR) << "Invalid command line: more than one action requested."; |
187 return false; | 188 return false; |
188 } | 189 } |
189 if (args[0] == ASCIIToUTF16(kInstallActionName)) { | 190 if (args[0] == kInstallActionName) { |
190 run_routine_ = &HostService::Install; | 191 run_routine_ = &HostService::Install; |
191 } else if (args[0] == ASCIIToUTF16(kRemoveActionName)) { | 192 } else if (args[0] == kRemoveActionName) { |
192 run_routine_ = &HostService::Remove; | 193 run_routine_ = &HostService::Remove; |
193 host_binary_required = false; | 194 host_binary_required = false; |
194 } else if (args[0] != ASCIIToUTF16(kRunActionName)) { | 195 } else if (args[0] != kRunActionName) { |
195 LOG(ERROR) << "Invalid command line: invalid action specified: " | 196 LOG(ERROR) << "Invalid command line: invalid action specified: " |
196 << args[0]; | 197 << args[0]; |
197 return false; | 198 return false; |
198 } | 199 } |
199 } | 200 } |
200 | 201 |
201 if (host_binary_required) { | 202 if (host_binary_required) { |
202 if (command_line->HasSwitch(kHostBinarySwitchName)) { | 203 if (command_line->HasSwitch(kHostBinarySwitchName)) { |
203 host_binary_ = command_line->GetSwitchValuePath(kHostBinarySwitchName); | 204 host_binary_ = command_line->GetSwitchValuePath(kHostBinarySwitchName); |
204 } else { | 205 } else { |
(...skipping 21 matching lines...) Expand all Loading... |
226 << "Failed to connect to the service control manager"; | 227 << "Failed to connect to the service control manager"; |
227 return kErrorExitCode; | 228 return kErrorExitCode; |
228 } | 229 } |
229 | 230 |
230 FilePath exe; | 231 FilePath exe; |
231 if (!PathService::Get(base::FILE_EXE, &exe)) { | 232 if (!PathService::Get(base::FILE_EXE, &exe)) { |
232 LOG(ERROR) << "Unable to retrieve the service binary path."; | 233 LOG(ERROR) << "Unable to retrieve the service binary path."; |
233 return kErrorExitCode; | 234 return kErrorExitCode; |
234 } | 235 } |
235 | 236 |
236 string16 name = StringPrintf(ASCIIToUTF16(kMuiStringFormat).c_str(), | 237 string16 name = StringPrintf(kMuiStringFormat, |
237 exe.value().c_str(), | 238 exe.value().c_str(), |
238 IDS_DISPLAY_SERVICE_NAME); | 239 IDS_DISPLAY_SERVICE_NAME); |
239 | 240 |
240 if (!file_util::AbsolutePath(&host_binary_) || | 241 if (!file_util::AbsolutePath(&host_binary_) || |
241 !file_util::PathExists(host_binary_)) { | 242 !file_util::PathExists(host_binary_)) { |
242 LOG(ERROR) << "Invalid host binary name: " << host_binary_.value(); | 243 LOG(ERROR) << "Invalid host binary name: " << host_binary_.value(); |
243 return kErrorExitCode; | 244 return kErrorExitCode; |
244 } | 245 } |
245 | 246 |
246 string16 command_line = StringPrintf( | 247 string16 command_line = StringPrintf(kServiceCommandLineFormat, |
247 ASCIIToUTF16(kServiceCommandLineFormat).c_str(), | 248 exe.value().c_str(), |
248 exe.value().c_str(), | 249 host_binary_.value().c_str()); |
249 host_binary_.value().c_str()); | |
250 ScopedScHandle service( | 250 ScopedScHandle service( |
251 CreateServiceW(scmanager, | 251 CreateServiceW(scmanager, |
252 service_name_.c_str(), | 252 service_name_.c_str(), |
253 name.c_str(), | 253 name.c_str(), |
254 SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG, | 254 SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG, |
255 SERVICE_WIN32_OWN_PROCESS, | 255 SERVICE_WIN32_OWN_PROCESS, |
256 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, | 256 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, |
257 command_line.c_str(), | 257 command_line.c_str(), |
258 NULL, | 258 NULL, |
259 NULL, | 259 NULL, |
260 ASCIIToUTF16(kServiceDependencies).c_str(), | 260 kServiceDependencies, |
261 NULL, | 261 NULL, |
262 NULL)); | 262 NULL)); |
263 | 263 |
264 if (service.IsValid()) { | 264 if (service.IsValid()) { |
265 // Set the service description if the service is freshly installed. | 265 // Set the service description if the service is freshly installed. |
266 string16 description = StringPrintf( | 266 string16 description = StringPrintf(kMuiStringFormat, |
267 ASCIIToUTF16(kMuiStringFormat).c_str(), | 267 exe.value().c_str(), |
268 exe.value().c_str(), | 268 IDS_SERVICE_DESCRIPTION); |
269 IDS_SERVICE_DESCRIPTION); | |
270 | 269 |
271 SERVICE_DESCRIPTIONW info; | 270 SERVICE_DESCRIPTIONW info; |
272 info.lpDescription = const_cast<LPWSTR>(description.c_str()); | 271 info.lpDescription = const_cast<LPWSTR>(description.c_str()); |
273 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &info)) { | 272 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &info)) { |
274 LOG_GETLASTERROR(ERROR) << "Failed to set the service description"; | 273 LOG_GETLASTERROR(ERROR) << "Failed to set the service description"; |
275 return kErrorExitCode; | 274 return kErrorExitCode; |
276 } | 275 } |
277 | 276 |
278 printf("The service has been installed successfully.\n"); | 277 printf("The service has been installed successfully.\n"); |
279 return kSuccessExitCode; | 278 return kSuccessExitCode; |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) { | 413 if (!SetConsoleCtrlHandler(&HostService::ConsoleControlHandler, TRUE)) { |
415 LOG_GETLASTERROR(ERROR) | 414 LOG_GETLASTERROR(ERROR) |
416 << "Failed to set console control handler"; | 415 << "Failed to set console control handler"; |
417 return result; | 416 return result; |
418 } | 417 } |
419 | 418 |
420 // Create a window for receiving session change notifications. | 419 // Create a window for receiving session change notifications. |
421 LPCWSTR atom = NULL; | 420 LPCWSTR atom = NULL; |
422 HWND window = NULL; | 421 HWND window = NULL; |
423 HINSTANCE instance = GetModuleHandle(NULL); | 422 HINSTANCE instance = GetModuleHandle(NULL); |
424 string16 window_class = ASCIIToUTF16(kSessionNotificationWindowClass); | |
425 | 423 |
426 WNDCLASSEX wc = {0}; | 424 WNDCLASSEX wc = {0}; |
427 wc.cbSize = sizeof(wc); | 425 wc.cbSize = sizeof(wc); |
428 wc.lpfnWndProc = base::win::WrappedWindowProc<SessionChangeNotificationProc>; | 426 wc.lpfnWndProc = base::win::WrappedWindowProc<SessionChangeNotificationProc>; |
429 wc.hInstance = instance; | 427 wc.hInstance = instance; |
430 wc.lpszClassName = window_class.c_str(); | 428 wc.lpszClassName = kSessionNotificationWindowClass; |
431 atom = reinterpret_cast<LPCWSTR>(RegisterClassExW(&wc)); | 429 atom = reinterpret_cast<LPCWSTR>(RegisterClassExW(&wc)); |
432 if (atom == NULL) { | 430 if (atom == NULL) { |
433 LOG_GETLASTERROR(ERROR) | 431 LOG_GETLASTERROR(ERROR) |
434 << "Failed to register the window class '" | 432 << "Failed to register the window class '" |
435 << kSessionNotificationWindowClass << "'"; | 433 << kSessionNotificationWindowClass << "'"; |
436 goto cleanup; | 434 goto cleanup; |
437 } | 435 } |
438 | 436 |
439 window = CreateWindowW(atom, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, instance, 0); | 437 window = CreateWindowW(atom, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, instance, 0); |
440 if (window == NULL) { | 438 if (window == NULL) { |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
599 } | 597 } |
600 | 598 |
601 remoting::HostService* service = remoting::HostService::GetInstance(); | 599 remoting::HostService* service = remoting::HostService::GetInstance(); |
602 if (!service->InitWithCommandLine(command_line)) { | 600 if (!service->InitWithCommandLine(command_line)) { |
603 usage(argv[0]); | 601 usage(argv[0]); |
604 return kUsageExitCode; | 602 return kUsageExitCode; |
605 } | 603 } |
606 | 604 |
607 return service->Run(); | 605 return service->Run(); |
608 } | 606 } |
OLD | NEW |