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_path.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/utf_string_conversions.h" | 23 #include "base/utf_string_conversions.h" |
24 #include "base/win/wrapped_window_proc.h" | 24 #include "base/win/wrapped_window_proc.h" |
25 | 25 |
26 #include "remoting/host/host_service_resource.h" | 26 #include "remoting/host/host_service_resource.h" |
27 #include "remoting/base/scoped_sc_handle_win.h" | 27 #include "remoting/base/scoped_sc_handle_win.h" |
28 #include "remoting/host/wts_console_observer_win.h" | 28 #include "remoting/host/wts_console_observer_win.h" |
29 #include "remoting/host/wts_session_process_launcher_win.h" | 29 #include "remoting/host/wts_session_process_launcher_win.h" |
30 | 30 |
31 using base::StringPrintf; | 31 using base::StringPrintf; |
32 | 32 |
33 namespace { | 33 namespace { |
34 | 34 |
35 // Service name. | 35 // Service name. |
36 const char kServiceName[] = "chromoting"; | 36 const char kServiceName[] = "chromoting"; |
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 char kMuiStringFormat[] = "@%ls,-%d"; |
39 const char kServiceDependencies[] = ""; | 39 const char kServiceDependencies[] = ""; |
40 | 40 |
| 41 const char kServiceCommandLineFormat[] = "\"%ls\" --host-binary=\"%ls\""; |
| 42 |
41 const DWORD kServiceStopTimeoutMs = 30 * 1000; | 43 const DWORD kServiceStopTimeoutMs = 30 * 1000; |
42 | 44 |
43 // Session id that does not represent any session. | 45 // Session id that does not represent any session. |
44 const uint32 kInvalidSession = 0xffffffff; | 46 const uint32 kInvalidSession = 0xffffffff; |
45 | 47 |
46 // A window class for the session change notifications window. | 48 // A window class for the session change notifications window. |
47 static const char kSessionNotificationWindowClass[] = | 49 static const char kSessionNotificationWindowClass[] = |
48 "Chromoting_SessionNotificationWindow"; | 50 "Chromoting_SessionNotificationWindow"; |
49 | 51 |
50 // Command line actions and switches: | 52 // Command line actions and switches: |
51 // "run" sumply runs the service as usual. | 53 // "run" sumply runs the service as usual. |
52 const char kRunActionName[] = "run"; | 54 const char kRunActionName[] = "run"; |
53 | 55 |
54 // "install" requests the service to be installed. | 56 // "install" requests the service to be installed. |
55 const char kInstallActionName[] = "install"; | 57 const char kInstallActionName[] = "install"; |
56 | 58 |
57 // "remove" uninstalls the service. | 59 // "remove" uninstalls the service. |
58 const char kRemoveActionName[] = "remove"; | 60 const char kRemoveActionName[] = "remove"; |
59 | 61 |
60 // "--console" runs the service interactively for debugging purposes. | 62 // "--console" runs the service interactively for debugging purposes. |
61 const char kConsoleSwitchName[] = "console"; | 63 const char kConsoleSwitchName[] = "console"; |
62 | 64 |
| 65 // "--host-binary" specifies the host binary to run in console session. |
| 66 const char kHostBinarySwitchName[] = "host-binary"; |
| 67 |
63 // "--help" or "--?" prints the usage message. | 68 // "--help" or "--?" prints the usage message. |
64 const char kHelpSwitchName[] = "help"; | 69 const char kHelpSwitchName[] = "help"; |
65 const char kQuestionSwitchName[] = "?"; | 70 const char kQuestionSwitchName[] = "?"; |
66 | 71 |
67 const char kUsageMessage[] = | 72 const char kUsageMessage[] = |
68 "\n" | 73 "\n" |
69 "Usage: %s [action] [options]\n" | 74 "Usage: %s [action] [options]\n" |
70 "\n" | 75 "\n" |
71 "Actions:\n" | 76 "Actions:\n" |
72 " run - Run the service. If no action specified 'run' is assumed.\n" | 77 " run - Run the service (default if no action was specified).\n" |
73 " install - Install the service.\n" | 78 " install - Install the service.\n" |
74 " remove - Uninstall the service.\n" | 79 " remove - Uninstall the service.\n" |
75 "\n" | 80 "\n" |
76 "Options:\n" | 81 "Options:\n" |
77 " --console - Run the service interactively for debugging purposes.\n" | 82 " --console - Run the service interactively for debugging purposes.\n" |
78 " --help, --? - Print this message.\n"; | 83 " --host-binary - Specifies the host binary to run in the console session.\n" |
| 84 " --help, --? - Print this message.\n"; |
79 | 85 |
80 // Exit codes: | 86 // Exit codes: |
81 const int kSuccessExitCode = 0; | 87 const int kSuccessExitCode = 0; |
82 const int kUsageExitCode = 1; | 88 const int kUsageExitCode = 1; |
83 const int kErrorExitCode = 2; | 89 const int kErrorExitCode = 2; |
84 | 90 |
85 void usage(const char* program_name) { | 91 void usage(const char* program_name) { |
86 fprintf(stderr, kUsageMessage, program_name); | 92 fprintf(stderr, kUsageMessage, program_name); |
87 } | 93 } |
88 | 94 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 } | 162 } |
157 | 163 |
158 HostService* HostService::GetInstance() { | 164 HostService* HostService::GetInstance() { |
159 return Singleton<HostService>::get(); | 165 return Singleton<HostService>::get(); |
160 } | 166 } |
161 | 167 |
162 bool HostService::InitWithCommandLine(const CommandLine* command_line) { | 168 bool HostService::InitWithCommandLine(const CommandLine* command_line) { |
163 CommandLine::StringVector args = command_line->GetArgs(); | 169 CommandLine::StringVector args = command_line->GetArgs(); |
164 | 170 |
165 // Choose the action to perform. | 171 // Choose the action to perform. |
| 172 bool host_binary_required = true; |
166 if (!args.empty()) { | 173 if (!args.empty()) { |
167 if (args.size() > 1) { | 174 if (args.size() > 1) { |
168 LOG(ERROR) << "Invalid command line: more than one action requested."; | 175 LOG(ERROR) << "Invalid command line: more than one action requested."; |
169 return false; | 176 return false; |
170 } | 177 } |
171 if (args[0] == ASCIIToUTF16(kInstallActionName)) { | 178 if (args[0] == ASCIIToUTF16(kInstallActionName)) { |
172 run_routine_ = &HostService::Install; | 179 run_routine_ = &HostService::Install; |
173 } else if (args[0] == ASCIIToUTF16(kRemoveActionName)) { | 180 } else if (args[0] == ASCIIToUTF16(kRemoveActionName)) { |
174 run_routine_ = &HostService::Remove; | 181 run_routine_ = &HostService::Remove; |
| 182 host_binary_required = false; |
175 } else if (args[0] != ASCIIToUTF16(kRunActionName)) { | 183 } else if (args[0] != ASCIIToUTF16(kRunActionName)) { |
176 LOG(ERROR) << "Invalid command line: invalid action specified: " | 184 LOG(ERROR) << "Invalid command line: invalid action specified: " |
177 << args[0]; | 185 << args[0]; |
178 return false; | 186 return false; |
179 } | 187 } |
180 } | 188 } |
181 | 189 |
| 190 if (host_binary_required) { |
| 191 if (command_line->HasSwitch(kHostBinarySwitchName)) { |
| 192 host_binary_ = command_line->GetSwitchValuePath(kHostBinarySwitchName); |
| 193 } else { |
| 194 LOG(ERROR) << "Invalid command line: --" << kHostBinarySwitchName |
| 195 << " is required."; |
| 196 return false; |
| 197 } |
| 198 } |
| 199 |
182 // Run interactively if needed. | 200 // Run interactively if needed. |
183 if (run_routine_ == &HostService::RunAsService && | 201 if (run_routine_ == &HostService::RunAsService && |
184 command_line->HasSwitch(kConsoleSwitchName)) { | 202 command_line->HasSwitch(kConsoleSwitchName)) { |
185 run_routine_ = &HostService::RunInConsole; | 203 run_routine_ = &HostService::RunInConsole; |
186 } | 204 } |
187 | 205 |
188 return true; | 206 return true; |
189 } | 207 } |
190 | 208 |
191 int HostService::Install() { | 209 int HostService::Install() { |
192 ScopedScHandle scmanager( | 210 ScopedScHandle scmanager( |
193 OpenSCManagerW(NULL, NULL, | 211 OpenSCManagerW(NULL, NULL, |
194 SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE)); | 212 SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE)); |
195 if (!scmanager.IsValid()) { | 213 if (!scmanager.IsValid()) { |
196 LOG_GETLASTERROR(ERROR) | 214 LOG_GETLASTERROR(ERROR) |
197 << "Failed to connect to the service control manager"; | 215 << "Failed to connect to the service control manager"; |
198 return kErrorExitCode; | 216 return kErrorExitCode; |
199 } | 217 } |
200 | 218 |
201 FilePath exe; | 219 FilePath exe; |
202 if (!PathService::Get(base::FILE_EXE, &exe)) { | 220 if (!PathService::Get(base::FILE_EXE, &exe)) { |
203 LOG(ERROR) << "Unable to retrieve the service binary path."; | 221 LOG(ERROR) << "Unable to retrieve the service binary path."; |
204 return kErrorExitCode; | 222 return kErrorExitCode; |
205 } | 223 } |
206 | 224 |
207 string16 name = StringPrintf(ASCIIToUTF16(kMuiStringFormat).c_str(), | 225 string16 name = StringPrintf(ASCIIToUTF16(kMuiStringFormat).c_str(), |
208 exe.value().c_str(), | 226 exe.value().c_str(), |
209 IDS_DISPLAY_SERVICE_NAME); | 227 IDS_DISPLAY_SERVICE_NAME); |
| 228 |
| 229 if (!file_util::AbsolutePath(&host_binary_) || |
| 230 !file_util::PathExists(host_binary_)) { |
| 231 LOG(ERROR) << "Invalid host binary name: " << host_binary_.value(); |
| 232 return kErrorExitCode; |
| 233 } |
| 234 |
| 235 string16 command_line = StringPrintf( |
| 236 ASCIIToUTF16(kServiceCommandLineFormat).c_str(), |
| 237 exe.value().c_str(), |
| 238 host_binary_.value().c_str()); |
210 ScopedScHandle service( | 239 ScopedScHandle service( |
211 CreateServiceW(scmanager, | 240 CreateServiceW(scmanager, |
212 service_name_.c_str(), | 241 service_name_.c_str(), |
213 name.c_str(), | 242 name.c_str(), |
214 SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG, | 243 SERVICE_QUERY_STATUS | SERVICE_CHANGE_CONFIG, |
215 SERVICE_WIN32_OWN_PROCESS, | 244 SERVICE_WIN32_OWN_PROCESS, |
216 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, | 245 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, |
217 exe.value().c_str(), | 246 command_line.c_str(), |
218 NULL, | 247 NULL, |
219 NULL, | 248 NULL, |
220 ASCIIToUTF16(kServiceDependencies).c_str(), | 249 ASCIIToUTF16(kServiceDependencies).c_str(), |
221 NULL, | 250 NULL, |
222 NULL)); | 251 NULL)); |
223 | 252 |
224 if (service.IsValid()) { | 253 if (service.IsValid()) { |
225 // Set the service description if the service is freshly installed. | 254 // Set the service description if the service is freshly installed. |
226 string16 description = StringPrintf( | 255 string16 description = StringPrintf( |
227 ASCIIToUTF16(kMuiStringFormat).c_str(), | 256 ASCIIToUTF16(kMuiStringFormat).c_str(), |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 | 344 |
316 printf("The service has been removed successfully.\n"); | 345 printf("The service has been removed successfully.\n"); |
317 return kSuccessExitCode; | 346 return kSuccessExitCode; |
318 } | 347 } |
319 | 348 |
320 int HostService::Run() { | 349 int HostService::Run() { |
321 return (this->*run_routine_)(); | 350 return (this->*run_routine_)(); |
322 } | 351 } |
323 | 352 |
324 void HostService::RunMessageLoop() { | 353 void HostService::RunMessageLoop() { |
325 WtsSessionProcessLauncher launcher(this); | 354 WtsSessionProcessLauncher launcher(this, host_binary_); |
326 | 355 |
327 // Run the service. | 356 // Run the service. |
328 message_loop_->Run(); | 357 message_loop_->Run(); |
329 | 358 |
330 // Clean up the observers by emulating detaching from the console. | 359 // Clean up the observers by emulating detaching from the console. |
331 shutting_down_ = true; | 360 shutting_down_ = true; |
332 OnSessionChange(); | 361 OnSessionChange(); |
333 | 362 |
334 // Release the control handler. | 363 // Release the control handler. |
335 stopped_event_.Signal(); | 364 stopped_event_.Signal(); |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 } | 567 } |
539 | 568 |
540 remoting::HostService* service = remoting::HostService::GetInstance(); | 569 remoting::HostService* service = remoting::HostService::GetInstance(); |
541 if (!service->InitWithCommandLine(command_line)) { | 570 if (!service->InitWithCommandLine(command_line)) { |
542 usage(argv[0]); | 571 usage(argv[0]); |
543 return kUsageExitCode; | 572 return kUsageExitCode; |
544 } | 573 } |
545 | 574 |
546 return service->Run(); | 575 return service->Run(); |
547 } | 576 } |
OLD | NEW |