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

Side by Side Diff: setup/setup_service.h

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 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
« no previous file with comments | « setup/setup_metrics.cc ('k') | setup/setup_service_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2007-2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15 //
16 // Sets up and controls the Google Update service.
17
18 // TODO(omaha3): Consolidate all the service related code into one file in base
19 // and one file in service.
20
21 #ifndef OMAHA_SETUP_SETUP_SERVICE_H_
22 #define OMAHA_SETUP_SETUP_SERVICE_H_
23
24 #include <windows.h>
25 #include "base/basictypes.h"
26 #include "omaha/base/constants.h"
27 #include "omaha/base/debug.h"
28 #include "omaha/base/error.h"
29 #include "omaha/base/logging.h"
30 #include "omaha/base/path.h"
31 #include "omaha/base/safe_format.h"
32 #include "omaha/base/scoped_any.h"
33 #include "omaha/base/service_utils.h"
34 #include "omaha/base/system_info.h"
35 #include "omaha/client/resource.h"
36 #include "omaha/common/command_line_builder.h"
37 #include "omaha/common/const_cmd_line.h"
38 #include "omaha/common/const_goopdate.h"
39 #include "omaha/service/service_main.h"
40
41 namespace omaha {
42
43 const uint32 kMaxQueryConfigBufferBytes = 8 * 1024;
44
45 template <typename T>
46 class SetupService {
47 public:
48 static HRESULT StartService() {
49 OPT_LOG(L1, (_T("[StartService]")));
50
51 scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
52 if (!scm) {
53 return HRESULTFromLastError();
54 }
55
56 CString service_name(T::GetCurrentServiceName());
57 scoped_service service(::OpenService(get(scm),
58 service_name,
59 SERVICE_QUERY_STATUS | SERVICE_START));
60 if (!service) {
61 return HRESULTFromLastError();
62 }
63
64 SERVICE_STATUS status = {0};
65 if (::QueryServiceStatus(get(service), &status)) {
66 if (status.dwCurrentState == SERVICE_RUNNING ||
67 status.dwCurrentState == SERVICE_START_PENDING) {
68 SETUP_LOG(L1, (_T("[QueryServiceStatus][Service already running][%u]"),
69 status.dwCurrentState));
70 return S_OK;
71 }
72 }
73
74 // Start the service.
75 if (::StartService(get(service), 0, NULL)) {
76 SETUP_LOG(L1, (_T("[StartService][started]")));
77 return S_OK;
78 }
79
80 HRESULT hr = HRESULTFromLastError();
81 ASSERT1(hr != HRESULT_FROM_WIN32(ERROR_SERVICE_ALREADY_RUNNING));
82 if (hr == HRESULT_FROM_WIN32(ERROR_SERVICE_ALREADY_RUNNING)) {
83 SETUP_LOG(L1, (_T("[StartService][ERROR_SERVICE_ALREADY_RUNNING]")));
84 return S_OK;
85 }
86
87 return hr;
88 }
89
90 static HRESULT StopService() {
91 SETUP_LOG(L1, (_T("[StopService]")));
92
93 CString service_name(T::GetCurrentServiceName());
94 return ServiceInstall::StopService(service_name);
95 }
96
97 static HRESULT InstallService(const TCHAR* file_path) {
98 ASSERT1(file_path);
99
100 // Append the arguments to be passed to the service entry point.
101
102 CString service_cmd_line(file_path);
103 CommandLineBuilder builder(T::commandline_mode());
104 SafeCStringAppendFormat(&service_cmd_line, _T(" %s"),
105 builder.GetCommandLineArgs());
106
107 SETUP_LOG(L2, (_T("[service command line][%s]"), service_cmd_line));
108
109 HRESULT hr = DoInstallService(service_cmd_line);
110 if (FAILED(hr)) {
111 SETUP_LOG(LE, (_T("[DoInstallService failed][0x%08x]"), hr));
112 return hr;
113 }
114
115 VERIFY1(SUCCEEDED(SetDescription(GetServiceDescription())));
116 VERIFY1(SUCCEEDED(SetDelayedAutoStart()));
117
118 return InstallCOMService();
119 }
120
121 // Uninstalls the service by:
122 // 1. unregistering it
123 // 2. deleting it from SCM if needed.
124 static HRESULT UninstallService() {
125 SETUP_LOG(L3, (_T("[UninstallService][%s]"), T::GetCurrentServiceName()));
126
127 HRESULT hr = StopService();
128 if (FAILED(hr)) {
129 SETUP_LOG(LW, (_T("[StopService failed][0x%08x]"), hr));
130 ASSERT1(HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) == hr);
131 }
132
133 VERIFY1(SUCCEEDED(UninstallCOMService()));
134
135 hr = DeleteService();
136 if (FAILED(hr)) {
137 OPT_LOG(LEVEL_ERROR, (_T("[Can't delete the service][0x%08x]"), hr));
138 return hr;
139 }
140
141 return S_OK;
142 }
143
144 static bool IsServiceInstalled() {
145 return ServiceInstall::IsServiceInstalled(T::GetCurrentServiceName());
146 }
147
148 private:
149 static HRESULT InstallCOMService() {
150 SETUP_LOG(L1, (_T("[InstallCOMService]")));
151
152 HRESULT hr = ServiceModule<T>().RegisterCOMService();
153
154 // We reset the _pAtlModule to allow for the case where multiple instances
155 // of ServiceModule are installed serially.
156 _pAtlModule = NULL;
157
158 return hr;
159 }
160
161 static HRESULT UninstallCOMService() {
162 SETUP_LOG(L1, (_T("[UninstallCOMService]")));
163
164 HRESULT hr = ServiceModule<T>().UnregisterCOMService();
165
166 // We reset the _pAtlModule to allow for the case where multiple instances
167 // of ServiceModule are uninstalled serially.
168 _pAtlModule = NULL;
169
170 return hr;
171 }
172
173 static HRESULT DoInstallService(const TCHAR* service_cmd_line) {
174 SETUP_LOG(L1, (_T("[DoInstallService][%s]"), service_cmd_line));
175
176 ASSERT1(service_cmd_line);
177
178 if (IsServiceInstalled()) {
179 // Lightweight upgrade of existing service.
180 HRESULT hr = UpgradeService(service_cmd_line);
181 ASSERT(SUCCEEDED(hr), (_T("[UpgradeService failed][0x%x]"), hr));
182 if (SUCCEEDED(hr)) {
183 return hr;
184 }
185
186 // Delete the previous version of the service. Then create a new service
187 // name, and fall through to install that.
188 VERIFY1(SUCCEEDED(DeleteService()));
189 VERIFY1(SUCCEEDED(CreateAndSetVersionedServiceNameInRegistry()));
190 ASSERT1(!IsServiceInstalled());
191 }
192
193 return DoInstallNewService(service_cmd_line);
194 }
195
196 static HRESULT DoInstallNewService(const TCHAR* service_cmd_line) {
197 ASSERT1(service_cmd_line);
198
199 scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
200 if (!scm) {
201 const DWORD error = ::GetLastError();
202 SETUP_LOG(LE, (_T("[Failed to open SC Manager][%u]"), error));
203 return HRESULT_FROM_WIN32(error);
204 }
205
206 CString service_name(T::GetCurrentServiceName());
207 CString service_display_name(GetCurrentServiceDisplayName());
208 scoped_service service(::CreateService(get(scm),
209 service_name,
210 service_display_name,
211 SERVICE_ALL_ACCESS,
212 SERVICE_WIN32_OWN_PROCESS,
213 T::service_start_type(),
214 SERVICE_ERROR_NORMAL,
215 service_cmd_line,
216 NULL,
217 NULL,
218 _T("RPCSS\0"),
219 NULL,
220 NULL));
221 if (!service) {
222 const DWORD error = ::GetLastError();
223 SETUP_LOG(LE, (_T("[CreateService failed][%u]"), error));
224 return HRESULT_FROM_WIN32(error);
225 }
226 SETUP_LOG(L1, (_T("[DoInstallNewService][service installed]")));
227 return S_OK;
228 }
229
230 static bool IsServiceCorrectlyConfigured(const TCHAR* service_cmd_line) {
231 scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT));
232 if (!scm) {
233 HRESULT hr = HRESULTFromLastError();
234 SETUP_LOG(LE, (_T("[Failed to open SC Manager][0x%x]"), hr));
235 return false;
236 }
237
238 CString service_name(T::GetCurrentServiceName());
239 scoped_service service(::OpenService(get(scm),
240 service_name,
241 SERVICE_QUERY_CONFIG));
242 if (!service) {
243 HRESULT hr = HRESULTFromLastError();
244 SETUP_LOG(LE, (_T("[OpenService SERVICE_QUERY_CONFIG fail][0x%x]"), hr));
245 return false;
246 }
247
248 // ::QueryServiceConfig expects a buffer of at most 8K bytes, according to
249 // documentation. While the size of the buffer can be dynamically computed,
250 // we just assume the maximum size for simplicity.
251 uint8 buffer[kMaxQueryConfigBufferBytes] = { 0 };
252 DWORD bytes_needed_ignored = 0;
253 QUERY_SERVICE_CONFIG* service_config =
254 reinterpret_cast<QUERY_SERVICE_CONFIG*>(buffer);
255 if (!::QueryServiceConfig(get(service),
256 service_config,
257 sizeof(buffer),
258 &bytes_needed_ignored)) {
259 HRESULT hr = HRESULTFromLastError();
260 SETUP_LOG(LE, (_T("[QueryServiceConfig failed][0x%x]"), hr));
261 return false;
262 }
263
264 bool does_service_cmd_line_match = false;
265 if (service_config->lpBinaryPathName == NULL || service_cmd_line == NULL) {
266 does_service_cmd_line_match =
267 (service_config->lpBinaryPathName == service_cmd_line);
268 } else {
269 does_service_cmd_line_match =
270 !_tcsicmp(service_config->lpBinaryPathName, service_cmd_line);
271 }
272 return service_config->dwServiceType == SERVICE_WIN32_OWN_PROCESS &&
273 service_config->dwStartType == T::service_start_type() &&
274 service_config->dwErrorControl == SERVICE_ERROR_NORMAL &&
275 does_service_cmd_line_match;
276 }
277
278 static HRESULT UpgradeService(const TCHAR* service_cmd_line) {
279 ASSERT1(service_cmd_line);
280 ASSERT1(IsServiceInstalled());
281
282 if (IsServiceCorrectlyConfigured(service_cmd_line)) {
283 return S_OK;
284 }
285
286 // Modify the configuration of the existing service.
287 HRESULT hr(StopService());
288 if (FAILED(hr)) {
289 SETUP_LOG(LE, (_T("[Can't stop the service][0x%08x]"), hr));
290 return hr;
291 }
292
293 scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
294 if (!scm) {
295 const DWORD error = ::GetLastError();
296 SETUP_LOG(LE, (_T("[Failed to open SC Manager][%u]"), error));
297 return HRESULT_FROM_WIN32(error);
298 }
299
300 CString service_name(T::GetCurrentServiceName());
301 scoped_service service(::OpenService(get(scm),
302 service_name,
303 SERVICE_CHANGE_CONFIG));
304 if (!service) {
305 const DWORD error = ::GetLastError();
306 SETUP_LOG(LE, (_T("[Failed to open service for update][%u]"), error));
307 return HRESULT_FROM_WIN32(error);
308 }
309
310 if (!::ChangeServiceConfig(get(service),
311 SERVICE_WIN32_OWN_PROCESS,
312 T::service_start_type(),
313 SERVICE_ERROR_NORMAL,
314 service_cmd_line,
315 NULL,
316 NULL,
317 NULL,
318 NULL,
319 NULL,
320 NULL)) {
321 const DWORD error = ::GetLastError();
322 SETUP_LOG(LE, (_T("[Failed to change service config][%u]"), error));
323 return HRESULT_FROM_WIN32(error);
324 }
325
326 SETUP_LOG(L3, (_T("[ChangeServiceConfig succeeded]")));
327 return S_OK;
328 }
329
330 static bool IsDelayedAutoStart() {
331 scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT));
332 if (!scm) {
333 HRESULT hr = HRESULTFromLastError();
334 SETUP_LOG(LE, (_T("[SC_MANAGER_CONNECT failed][0x%x]"), hr));
335 return false;
336 }
337
338 CString name(T::GetCurrentServiceName());
339 scoped_service service(::OpenService(get(scm), name, SERVICE_QUERY_CONFIG));
340 if (!service) {
341 HRESULT hr = HRESULTFromLastError();
342 SETUP_LOG(LE, (_T("[SERVICE_QUERY_CONFIG failed][%s][0x%x]"), name, hr));
343 return false;
344 }
345
346 uint8 buffer[kMaxQueryConfigBufferBytes] = { 0 };
347 DWORD bytes_needed_ignored = 0;
348 SERVICE_DELAYED_AUTO_START_INFO* service_config =
349 reinterpret_cast<SERVICE_DELAYED_AUTO_START_INFO*>(buffer);
350 if (!::QueryServiceConfig2(get(service),
351 SERVICE_CONFIG_DELAYED_AUTO_START_INFO,
352 buffer,
353 sizeof(buffer),
354 &bytes_needed_ignored)) {
355 HRESULT hr = HRESULTFromLastError();
356 SETUP_LOG(LE, (_T("[Query SERVICE_CONFIG_DELAYED_AUTO_START_INFO failed]")
357 _T("[0x%x]"), hr));
358 return false;
359 }
360
361 return !!service_config->fDelayedAutostart;
362 }
363
364 static HRESULT SetDelayedAutoStart() {
365 if (!SystemInfo::IsRunningOnVistaOrLater()) {
366 return S_OK;
367 }
368
369 ASSERT1(IsServiceInstalled());
370
371 if (IsDelayedAutoStart()) {
372 return S_OK;
373 }
374
375 scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
376 if (!scm) {
377 HRESULT hr = HRESULTFromLastError();
378 SETUP_LOG(LE, (_T("[OpenSCManager failed][0x%x]"), hr));
379 return hr;
380 }
381
382 CString service_name(T::GetCurrentServiceName());
383 scoped_service service(::OpenService(get(scm),
384 service_name,
385 SERVICE_CHANGE_CONFIG));
386 if (!service) {
387 HRESULT hr = HRESULTFromLastError();
388 SETUP_LOG(LE, (_T("[OpenService failed][0x%x]"), hr));
389 return hr;
390 }
391
392 SERVICE_DELAYED_AUTO_START_INFO auto_start_info = {TRUE};
393 if (!::ChangeServiceConfig2(get(service),
394 SERVICE_CONFIG_DELAYED_AUTO_START_INFO,
395 &auto_start_info)) {
396 HRESULT hr = HRESULTFromLastError();
397 SETUP_LOG(LE, (_T("[ChangeServiceConfig2 failed][0x%x]"), hr));
398 return hr;
399 }
400
401 SETUP_LOG(L3, (_T("[SetDelayedAutoStart succeeded]")));
402 return S_OK;
403 }
404
405 static HRESULT DeleteService() {
406 SETUP_LOG(L3, (_T("[DeleteService][%s]"), T::GetCurrentServiceName()));
407
408 scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
409 if (!scm) {
410 return HRESULTFromLastError();
411 }
412 scoped_service service(::OpenService(get(scm),
413 T::GetCurrentServiceName(),
414 SERVICE_CHANGE_CONFIG | DELETE));
415 if (!service) {
416 return HRESULTFromLastError();
417 }
418
419 if (!::DeleteService(get(service))) {
420 HRESULT hr = HRESULTFromLastError();
421 SETUP_LOG(LW, (_T("[DeleteService failed][0x%x]"), hr));
422 if (hr != HRESULT_FROM_WIN32(ERROR_SERVICE_MARKED_FOR_DELETE)) {
423 return hr;
424 }
425 }
426
427 return S_OK;
428 }
429
430 static bool DoesDescriptionMatch(const TCHAR* description) {
431 ASSERT1(description);
432
433 scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT));
434 if (!scm) {
435 HRESULT hr = HRESULTFromLastError();
436 SETUP_LOG(LE, (_T("[SC_MANAGER_CONNECT failed][0x%x]"), hr));
437 return false;
438 }
439
440 CString name(T::GetCurrentServiceName());
441 scoped_service service(::OpenService(get(scm), name, SERVICE_QUERY_CONFIG));
442 if (!service) {
443 HRESULT hr = HRESULTFromLastError();
444 SETUP_LOG(LE, (_T("[SERVICE_QUERY_CONFIG failed][%s][0x%x]"), name, hr));
445 return false;
446 }
447
448 uint8 buffer[kMaxQueryConfigBufferBytes] = { 0 };
449 DWORD bytes_needed_ignored = 0;
450 SERVICE_DESCRIPTION* service_config =
451 reinterpret_cast<SERVICE_DESCRIPTION*>(buffer);
452 if (!::QueryServiceConfig2(get(service),
453 SERVICE_CONFIG_DESCRIPTION,
454 buffer,
455 sizeof(buffer),
456 &bytes_needed_ignored)) {
457 HRESULT hr = HRESULTFromLastError();
458 SETUP_LOG(LE, (_T("[QuerySERVICE_CONFIG_DESCRIPTION failed][0x%x]"), hr));
459 return false;
460 }
461
462 if (service_config->lpDescription == NULL || description == NULL) {
463 return (service_config->lpDescription == description);
464 }
465
466 return !_tcsicmp(service_config->lpDescription, description);
467 }
468
469 static HRESULT SetDescription(const TCHAR* description) {
470 ASSERT1(description);
471
472 if (DoesDescriptionMatch(description)) {
473 return S_OK;
474 }
475
476 scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
477 if (!scm) {
478 return HRESULTFromLastError();
479 }
480
481 CString name(T::GetCurrentServiceName());
482
483 // Opening the service with less rights fails the ChangeServiceConfig2 call
484 // with E_ACCESSDENIED.
485 scoped_service service(::OpenService(get(scm), name, SERVICE_ALL_ACCESS));
486 if (!service) {
487 return HRESULTFromLastError();
488 }
489 SERVICE_DESCRIPTION info = { const_cast<TCHAR*>(description) };
490 if (!::ChangeServiceConfig2(get(service),
491 SERVICE_CONFIG_DESCRIPTION,
492 &info)) {
493 return HRESULTFromLastError();
494 }
495 SETUP_LOG(L3, (_T("[service description changed successfully]")));
496 return S_OK;
497 }
498
499 static CString GetCurrentServiceDisplayName() {
500 CORE_LOG(L3, (_T("[GetCurrentServiceDisplayName]")));
501
502 CString product_name;
503 VERIFY1(product_name.LoadString(IDS_PRODUCT_DISPLAY_NAME));
504
505 CString display_name;
506 display_name.FormatMessage(IDS_SERVICE_DISPLAY_NAME, product_name);
507 display_name.AppendFormat(_T(" (%s)"), T::GetCurrentServiceName());
508 return display_name;
509 }
510
511 static CString GetServiceDescription() {
512 // TODO(omaha3): Do we need a different service description for the medium
513 // service?
514
515 CString company_name;
516 VERIFY1(company_name.LoadString(IDS_FRIENDLY_COMPANY_NAME));
517
518 CString service_description;
519 service_description.FormatMessage(IDS_SERVICE_DESCRIPTION, company_name);
520 return service_description;
521 }
522
523 static HRESULT CreateAndSetVersionedServiceNameInRegistry() {
524 CORE_LOG(L3, (_T("CreateAndSetVersionedServiceNameInRegistry")));
525 return goopdate_utils::CreateAndSetVersionedNameInRegistry(true,
526 T::default_name(), T::reg_name());
527 }
528
529 friend class SetupServiceTest;
530 friend class CoreUtilsTest;
531
532 DISALLOW_IMPLICIT_CONSTRUCTORS(SetupService);
533 };
534
535 typedef SetupService<Update3ServiceMode> SetupUpdate3Service;
536 typedef SetupService<UpdateMediumServiceMode> SetupUpdateMediumService;
537
538 } // namespace omaha
539
540 #endif // OMAHA_SETUP_SETUP_SERVICE_H_
OLDNEW
« no previous file with comments | « setup/setup_metrics.cc ('k') | setup/setup_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698