| OLD | NEW |
| (Empty) |
| 1 // Copyright 2006-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 // The service is a bootstrap for a local system process to start | |
| 17 // when the computer starts. The service shuts itself down in 30 seconds. | |
| 18 // | |
| 19 // The service can be started in one of two modes: | |
| 20 // * As a regular service, typically at system startup. | |
| 21 // * As a COM service, typically by an Omaha client using IGoogleUpdateCore. | |
| 22 // The COM case is distinguished from the regular service case by registering a | |
| 23 // ServiceParameters command line in the AppID registration. | |
| 24 // | |
| 25 // In all cases, the service initializes COM, and allows for IGoogleUpdateCore | |
| 26 // clients to connect to the service. In the regular service case, the service | |
| 27 // shuts down after a small idle check timeout, provided that there are no COM | |
| 28 // clients connected. In the COM server case, and in the case where there are | |
| 29 // COM clients connected in the regular service case, the service will shut down | |
| 30 // when the last client disconnects. | |
| 31 // | |
| 32 // To be exact, the service will initiate shutdown in all cases when the ATL | |
| 33 // module count drops to zero. | |
| 34 // | |
| 35 // ATL does not allow for directly reusing the delayed COM shutdown mechanism | |
| 36 // available for Local servers. The assumption likely being that services run | |
| 37 // forever. Since we do not want our service to run forever, we override some | |
| 38 // of the functions to get the same effect. | |
| 39 | |
| 40 #ifndef OMAHA_SERVICE_SERVICE_MAIN_H_ | |
| 41 #define OMAHA_SERVICE_SERVICE_MAIN_H_ | |
| 42 | |
| 43 #include <atlbase.h> | |
| 44 #include <atlcom.h> | |
| 45 #include "base/basictypes.h" | |
| 46 #include "base/scoped_ptr.h" | |
| 47 #include "omaha/base/atlregmapex.h" | |
| 48 #include "omaha/base/debug.h" | |
| 49 // Use client/resource.h because it does not use StringFormatter and some of the | |
| 50 // strings are only used during Setup, which is part of the client. | |
| 51 // TODO(omaha3): It is a little unexpected to access strings in a header. It | |
| 52 // would be nice to avoid that. Also, this file is included by both client | |
| 53 // (setup_service.cc) and server (goopdate.cc) code. | |
| 54 #include "omaha/client/resource.h" | |
| 55 #include "omaha/common/command_line_builder.h" | |
| 56 #include "omaha/common/const_cmd_line.h" | |
| 57 #include "omaha/common/const_goopdate.h" | |
| 58 #include "omaha/common/goopdate_utils.h" | |
| 59 #include "omaha/core/google_update_core.h" | |
| 60 #include "omaha/goopdate/google_update3.h" | |
| 61 #include "omaha/goopdate/non_localized_resource.h" | |
| 62 #include "omaha/goopdate/ondemand.h" | |
| 63 #include "omaha/goopdate/update3web.h" | |
| 64 #include "omaha/goopdate/worker.h" | |
| 65 #include "omaha/net/network_config.h" | |
| 66 | |
| 67 namespace omaha { | |
| 68 | |
| 69 class Update3ServiceMode { | |
| 70 public: | |
| 71 static CommandLineMode commandline_mode(); | |
| 72 static CString reg_name(); | |
| 73 static CString default_name(); | |
| 74 static DWORD service_start_type(); | |
| 75 static _ATL_OBJMAP_ENTRY* object_map(); | |
| 76 static bool allow_access_from_medium(); | |
| 77 static CString app_id_string(); | |
| 78 static CString GetCurrentServiceName(); | |
| 79 static HRESULT PreMessageLoop(); | |
| 80 }; | |
| 81 | |
| 82 class UpdateMediumServiceMode { | |
| 83 public: | |
| 84 static CommandLineMode commandline_mode(); | |
| 85 static CString reg_name(); | |
| 86 static CString default_name(); | |
| 87 static DWORD service_start_type(); | |
| 88 static _ATL_OBJMAP_ENTRY* object_map(); | |
| 89 static bool allow_access_from_medium(); | |
| 90 static CString app_id_string(); | |
| 91 static CString GetCurrentServiceName(); | |
| 92 static HRESULT PreMessageLoop(); | |
| 93 }; | |
| 94 | |
| 95 #pragma warning(push) | |
| 96 // C4640: construction of local static object is not thread-safe | |
| 97 #pragma warning(disable : 4640) | |
| 98 | |
| 99 template <typename T> | |
| 100 class ServiceModule | |
| 101 : public CAtlServiceModuleT<ServiceModule<T>, IDS_SERVICE_NAME> { | |
| 102 public: | |
| 103 typedef CAtlServiceModuleT<ServiceModule, IDS_SERVICE_NAME> Base; | |
| 104 | |
| 105 DECLARE_REGISTRY_APPID_RESOURCEID_EX(IDR_GOOGLE_UPDATE3_SERVICE_APPID, | |
| 106 T::app_id_string()) | |
| 107 | |
| 108 BEGIN_REGISTRY_MAP() | |
| 109 REGMAP_ENTRY(_T("DESCRIPTION"), _T("ServiceModule")) | |
| 110 REGMAP_ENTRY(_T("FILENAME"), kServiceFileName) | |
| 111 END_REGISTRY_MAP() | |
| 112 | |
| 113 ServiceModule() | |
| 114 : service_thread_(NULL), | |
| 115 is_service_com_server_(false) { | |
| 116 SERVICE_LOG(L1, (_T("[ServiceModule]"))); | |
| 117 _tcscpy(m_szServiceName, T::GetCurrentServiceName()); | |
| 118 } | |
| 119 | |
| 120 ~ServiceModule() { | |
| 121 SERVICE_LOG(L1, (_T("[~ServiceModule]"))); | |
| 122 ASSERT1(!service_thread_); | |
| 123 | |
| 124 // ServiceModule is typically created on the stack. We cannot reset the | |
| 125 // _pAtlModule here, because objects are destroyed at destructor unwind | |
| 126 // time, and require access to the module. | |
| 127 } | |
| 128 | |
| 129 HRESULT InitializeSecurity() throw() { | |
| 130 SERVICE_LOG(L3, (_T("[InitializeSecurity]"))); | |
| 131 | |
| 132 return InitializeServerSecurity(T::allow_access_from_medium()); | |
| 133 } | |
| 134 | |
| 135 void ServiceMain(DWORD argc, LPTSTR* argv) throw() { | |
| 136 ASSERT1(argc <= 2); | |
| 137 is_service_com_server_ = | |
| 138 argc == 2 && !CString(argv[1]).CompareNoCase(kCmdLineServiceComServer); | |
| 139 SERVICE_LOG(L3, (_T("[ServiceMain][is_service_com_server_][%d]"), | |
| 140 is_service_com_server_)); | |
| 141 Base::ServiceMain(argc, argv); | |
| 142 } | |
| 143 | |
| 144 HRESULT RegisterClassObjects(DWORD class_context, | |
| 145 DWORD flags) throw() { | |
| 146 SERVICE_LOG(L3, (_T("[RegisterClassObjects]"))); | |
| 147 for (_ATL_OBJMAP_ENTRY* objmap_entry = T::object_map(); | |
| 148 objmap_entry->pclsid != NULL; | |
| 149 objmap_entry++) { | |
| 150 HRESULT hr = objmap_entry->RegisterClassObject(class_context, flags); | |
| 151 if (FAILED(hr)) { | |
| 152 SERVICE_LOG(LE, (_T("[RegisterClassObject failed][%s][0x%x]"), | |
| 153 GuidToString(*objmap_entry->pclsid), hr)); | |
| 154 return hr; | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 return S_OK; | |
| 159 } | |
| 160 | |
| 161 HRESULT RevokeClassObjects() throw() { | |
| 162 SERVICE_LOG(L3, (_T("[RevokeClassObjects]"))); | |
| 163 for (_ATL_OBJMAP_ENTRY* objmap_entry = T::object_map(); | |
| 164 objmap_entry->pclsid != NULL; | |
| 165 objmap_entry++) { | |
| 166 HRESULT hr = objmap_entry->RevokeClassObject(); | |
| 167 if (FAILED(hr)) { | |
| 168 SERVICE_LOG(LE, (_T("[RevokeClassObject failed][%s][0x%x]"), | |
| 169 GuidToString(*objmap_entry->pclsid), hr)); | |
| 170 return hr; | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 return S_OK; | |
| 175 } | |
| 176 | |
| 177 HRESULT RegisterServer(BOOL, const CLSID* = NULL) throw() { | |
| 178 SERVICE_LOG(L3, (_T("[RegisterServer]"))); | |
| 179 for (_ATL_OBJMAP_ENTRY* objmap_entry = T::object_map(); | |
| 180 objmap_entry->pclsid != NULL; | |
| 181 objmap_entry++) { | |
| 182 HRESULT hr = objmap_entry->pfnUpdateRegistry(TRUE); | |
| 183 if (FAILED(hr)) { | |
| 184 SERVICE_LOG(LE, (_T("[pfnUpdateRegistry failed][%s][0x%x]"), | |
| 185 GuidToString(*objmap_entry->pclsid), hr)); | |
| 186 return hr; | |
| 187 } | |
| 188 | |
| 189 hr = AtlRegisterClassCategoriesHelper(*objmap_entry->pclsid, | |
| 190 objmap_entry->pfnGetCategoryMap(), | |
| 191 TRUE); | |
| 192 if (FAILED(hr)) { | |
| 193 SERVICE_LOG(LE, (_T("[RegisterServer fail][%s][0x%x]"), | |
| 194 GuidToString(*objmap_entry->pclsid), hr)); | |
| 195 return hr; | |
| 196 } | |
| 197 } | |
| 198 | |
| 199 return S_OK; | |
| 200 } | |
| 201 | |
| 202 HRESULT UnregisterServer(BOOL, const CLSID* = NULL) throw() { | |
| 203 SERVICE_LOG(L3, (_T("[UnregisterServer]"))); | |
| 204 for (_ATL_OBJMAP_ENTRY* objmap_entry = T::object_map(); | |
| 205 objmap_entry->pclsid != NULL; | |
| 206 objmap_entry++) { | |
| 207 HRESULT hr = AtlRegisterClassCategoriesHelper(*objmap_entry->pclsid, | |
| 208 objmap_entry->pfnGetCategoryMap(), | |
| 209 FALSE); | |
| 210 if (FAILED(hr)) { | |
| 211 SERVICE_LOG(LE, (_T("[RegisterServer fail][%s][0x%x]"), | |
| 212 GuidToString(*objmap_entry->pclsid), hr)); | |
| 213 return hr; | |
| 214 } | |
| 215 | |
| 216 hr = objmap_entry->pfnUpdateRegistry(FALSE); | |
| 217 if (FAILED(hr)) { | |
| 218 SERVICE_LOG(LE, (_T("[pfnUpdateRegistry failed][%s][0x%x]"), | |
| 219 GuidToString(*objmap_entry->pclsid), hr)); | |
| 220 return hr; | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 return S_OK; | |
| 225 } | |
| 226 | |
| 227 HRESULT RegisterCOMService() { | |
| 228 SERVICE_LOG(L3, (_T("[RegisterCOMService]"))); | |
| 229 HRESULT hr = UpdateRegistryAppId(TRUE); | |
| 230 if (FAILED(hr)) { | |
| 231 SERVICE_LOG(LE, (_T("[UpdateRegistryAppId failed][0x%x]"), hr)); | |
| 232 return hr; | |
| 233 } | |
| 234 | |
| 235 RegKey key_app_id; | |
| 236 hr = key_app_id.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE); | |
| 237 if (FAILED(hr)) { | |
| 238 SERVICE_LOG(LE, (_T("[Could not open HKLM\\AppID][0x%x]"), hr)); | |
| 239 return hr; | |
| 240 } | |
| 241 | |
| 242 RegKey key; | |
| 243 hr = key.Create(key_app_id.Key(), GetAppIdT()); | |
| 244 if (FAILED(hr)) { | |
| 245 SERVICE_LOG(LE, (_T("[Fail open HKLM-AppID-%s][0x%x]"), GetAppId(), hr)); | |
| 246 return hr; | |
| 247 } | |
| 248 | |
| 249 // m_szServiceName is set in the constructor. | |
| 250 hr = key.SetValue(_T("LocalService"), m_szServiceName); | |
| 251 if (FAILED(hr)) { | |
| 252 SERVICE_LOG(LE, (_T("[Could not set LocalService value][0x%x]"), hr)); | |
| 253 return hr; | |
| 254 } | |
| 255 | |
| 256 // The SCM will pass this switch to ServiceMain() during COM activation. | |
| 257 hr = key.SetValue(_T("ServiceParameters"), kCmdLineServiceComServer); | |
| 258 if (FAILED(hr)) { | |
| 259 SERVICE_LOG(LE, (_T("[Set ServiceParameters value failed][0x%x]"), hr)); | |
| 260 return hr; | |
| 261 } | |
| 262 | |
| 263 return RegisterServer(FALSE); | |
| 264 } | |
| 265 | |
| 266 HRESULT UnregisterCOMService() { | |
| 267 SERVICE_LOG(L3, (_T("[UnregisterCOMService]"))); | |
| 268 HRESULT hr = UnregisterServer(FALSE); | |
| 269 if (FAILED(hr)) { | |
| 270 SERVICE_LOG(LE, (_T("[UnregisterServer failed][0x%x]"), hr)); | |
| 271 return hr; | |
| 272 } | |
| 273 | |
| 274 return UpdateRegistryAppId(FALSE); | |
| 275 } | |
| 276 | |
| 277 HRESULT PreMessageLoop(int show_cmd) { | |
| 278 UNREFERENCED_PARAMETER(show_cmd); | |
| 279 | |
| 280 SERVICE_LOG(L1, (_T("[PreMessageLoop]"))); | |
| 281 | |
| 282 m_dwThreadID = ::GetCurrentThreadId(); | |
| 283 service_thread_ = ::OpenThread(SYNCHRONIZE, false, m_dwThreadID); | |
| 284 | |
| 285 if (is_service_com_server_) { | |
| 286 return InitializeCOMServer(); | |
| 287 } | |
| 288 | |
| 289 // This is the regular service case. Call T::PreMessageLoop() and exit. | |
| 290 SetServiceStatus(SERVICE_RUNNING); | |
| 291 | |
| 292 HRESULT hr = T::PreMessageLoop(); | |
| 293 if (FAILED(hr)) { | |
| 294 SERVICE_LOG(LE, (_T("[T::PreMessageLoop() failed][0x%x]"), hr)); | |
| 295 } | |
| 296 | |
| 297 SetServiceStatus(SERVICE_STOP_PENDING); | |
| 298 | |
| 299 // S_FALSE is returned to exit the service immediately. | |
| 300 return S_FALSE; | |
| 301 } | |
| 302 | |
| 303 HRESULT PostMessageLoop() { | |
| 304 SERVICE_LOG(L1, (_T("[PostMessageLoop]"))); | |
| 305 | |
| 306 if (!is_service_com_server_) { | |
| 307 return S_OK; | |
| 308 } | |
| 309 | |
| 310 return Base::PostMessageLoop(); | |
| 311 } | |
| 312 | |
| 313 int Main(int show_cmd) { | |
| 314 if (CAtlBaseModule::m_bInitFailed) { | |
| 315 SERVICE_LOG(LE, (_T("[CAtlBaseModule init failed]"))); | |
| 316 return -1; | |
| 317 } | |
| 318 | |
| 319 return static_cast<int>(Start(show_cmd)); | |
| 320 } | |
| 321 | |
| 322 // This is cloned from CAtlExeModuleT.Lock(). The one difference is the call | |
| 323 // to ::CoAddRefServerProcess(). See the description for Unlock() below for | |
| 324 // further information. | |
| 325 virtual LONG Lock() throw() { | |
| 326 ::CoAddRefServerProcess(); | |
| 327 LONG retval = CComGlobalsThreadModel::Increment(&m_nLockCnt); | |
| 328 SERVICE_LOG(L3, (_T("[ServiceModule::Lock][%d]"), retval)); | |
| 329 return retval; | |
| 330 } | |
| 331 | |
| 332 // This is cloned from CAtlExeModuleT.Unlock(). The differences are: | |
| 333 // | |
| 334 // * the call to ::CoReleaseServerProcess(), to ensure that the class | |
| 335 // factories are suspended once the lock count drops to zero. This fixes a | |
| 336 // a race condition where an activation request could come in in the middle | |
| 337 // of shutting down. This shutdown mechanism works with free threaded servers. | |
| 338 // | |
| 339 // There are race issues with the ATL delayed shutdown mechanism, hence the | |
| 340 // associated code has been eliminated, and we have an assert to make sure | |
| 341 // m_bDelayShutdown is not set. | |
| 342 // | |
| 343 // * the call to "OnStop()" instead of the "::PostThreadMessage(m_dwMainThre". | |
| 344 // OnStop() correctly sets the service status to SERVICE_STOP_PENDING, and | |
| 345 // posts a WM_QUIT to the service thread. | |
| 346 virtual LONG Unlock() throw() { | |
| 347 ASSERT1(!m_bDelayShutdown); | |
| 348 | |
| 349 ::CoReleaseServerProcess(); | |
| 350 LONG retval = CComGlobalsThreadModel::Decrement(&m_nLockCnt); | |
| 351 SERVICE_LOG(L3, (_T("[ServiceModule::Unlock][%d]"), retval)); | |
| 352 | |
| 353 if (retval == 0) { | |
| 354 OnStop(); | |
| 355 } | |
| 356 | |
| 357 return retval; | |
| 358 } | |
| 359 | |
| 360 // This is cloned from CAtlExeModuleT.MonitorShutdown(). The only difference | |
| 361 // is the call to "OnStop()" instead of the | |
| 362 // "::PostThreadMessage(m_dwMainThreadID". | |
| 363 void MonitorShutdown() throw() { | |
| 364 SERVICE_LOG(L3, (_T("[MonitorShutdown]"))); | |
| 365 | |
| 366 while (true) { | |
| 367 ::WaitForSingleObject(m_hEventShutdown, INFINITE); | |
| 368 SERVICE_LOG(L4, (_T("[Infinite Wait][%d][%d]"), m_bActivity, m_nLockCnt)); | |
| 369 | |
| 370 DWORD wait = 0; | |
| 371 do { | |
| 372 m_bActivity = false; | |
| 373 wait = ::WaitForSingleObject(m_hEventShutdown, m_dwTimeOut); | |
| 374 } while (wait == WAIT_OBJECT_0); | |
| 375 | |
| 376 SERVICE_LOG(L4, (_T("[MonitorShutdown][%d][%d]"), | |
| 377 m_bActivity, m_nLockCnt)); | |
| 378 if (!m_bActivity && m_nLockCnt == 0) { | |
| 379 ::CoSuspendClassObjects(); | |
| 380 if (m_nLockCnt == 0) { | |
| 381 break; | |
| 382 } | |
| 383 } | |
| 384 } | |
| 385 | |
| 386 ::CloseHandle(m_hEventShutdown); | |
| 387 OnStop(); | |
| 388 } | |
| 389 | |
| 390 // This is cloned from CAtlExeModuleT.StartMonitor(). | |
| 391 HANDLE StartMonitor() throw() { | |
| 392 SERVICE_LOG(L3, (_T("[StartMonitor]"))); | |
| 393 m_hEventShutdown = ::CreateEvent(NULL, false, false, NULL); | |
| 394 if (m_hEventShutdown == NULL) { | |
| 395 return NULL; | |
| 396 } | |
| 397 | |
| 398 DWORD thread_id(0); | |
| 399 HANDLE monitor = ::CreateThread(NULL, 0, MonitorProc, this, 0, &thread_id); | |
| 400 if (monitor == NULL) { | |
| 401 ::CloseHandle(m_hEventShutdown); | |
| 402 } | |
| 403 | |
| 404 return monitor; | |
| 405 } | |
| 406 | |
| 407 // This is cloned from CAtlExeModuleT.MonitorProc(). | |
| 408 static DWORD WINAPI MonitorProc(void* pv) throw() { | |
| 409 SERVICE_LOG(L3, (_T("[MonitorProc]"))); | |
| 410 ServiceModule* service_module = static_cast<ServiceModule*>(pv); | |
| 411 ASSERT1(service_module); | |
| 412 | |
| 413 service_module->MonitorShutdown(); | |
| 414 return 0; | |
| 415 } | |
| 416 | |
| 417 private: | |
| 418 // Should only be called from the client, such as during Setup, since it only | |
| 419 // supports one language. | |
| 420 // Assumes the resources have been loaded. | |
| 421 static CString GetServiceDescription() { | |
| 422 CString company_name; | |
| 423 VERIFY1(company_name.LoadString(IDS_FRIENDLY_COMPANY_NAME)); | |
| 424 CString description; | |
| 425 description.FormatMessage(IDS_SERVICE_DESCRIPTION, company_name); | |
| 426 return description; | |
| 427 } | |
| 428 | |
| 429 HRESULT InitializeCOMServer() { | |
| 430 SERVICE_LOG(L1, (_T("[InitializeCOMServer]"))); | |
| 431 | |
| 432 // Initialize COM security right at the beginning, because Worker | |
| 433 // initialization can cause interface marshaling. The first few lines below | |
| 434 // are adapted from the beginning of CAtlServiceModuleT::PreMessageLoop(). | |
| 435 ASSERT1(m_bService); | |
| 436 HRESULT hr = InitializeSecurity(); | |
| 437 if (FAILED(hr)) { | |
| 438 return hr; | |
| 439 } | |
| 440 | |
| 441 DisableCOMExceptionHandling(); | |
| 442 | |
| 443 NetworkConfigManager::set_is_machine(true); | |
| 444 | |
| 445 // Create NetworkConfigManager singleton by referencing it. | |
| 446 NetworkConfigManager::Instance(); | |
| 447 | |
| 448 // Register and resume the COM class objects. We call the CAtlExeModuleT | |
| 449 // member instead of CAtlServiceModuleT, because the latter also tries to | |
| 450 // initialize security, which we have already done above. | |
| 451 return CAtlExeModuleT<ServiceModule>::PreMessageLoop(SW_HIDE); | |
| 452 } | |
| 453 | |
| 454 // When Start executes, it blocks on StartServiceCtrlDispatcher. | |
| 455 // Internally, the SCM creates a service thread which starts executing code | |
| 456 // specified by SERVICE_TABLE_ENTRY. The ATL code then calls PreMessageLoop | |
| 457 // and PostMessageLoop on this thread. When the service stops, the execution | |
| 458 // flow returns from StartServiceCtrlDispatcher and the main thread blocks | |
| 459 // waiting on the service thread to exit. | |
| 460 // Before synchronizing the main thread and the service thread, race condition | |
| 461 // resulted in http://b/1134747. | |
| 462 HRESULT Start(int show_cmd) { | |
| 463 SERVICE_LOG(L1, (_T("[Start]"))); | |
| 464 UNREFERENCED_PARAMETER(show_cmd); | |
| 465 | |
| 466 SERVICE_TABLE_ENTRY st[] = { | |
| 467 { m_szServiceName, Base::_ServiceMain }, | |
| 468 { NULL, NULL } | |
| 469 }; | |
| 470 | |
| 471 m_status.dwWin32ExitCode = 0; | |
| 472 if (!::StartServiceCtrlDispatcher(st)) { | |
| 473 m_status.dwWin32ExitCode = ::GetLastError(); | |
| 474 } | |
| 475 | |
| 476 if (service_thread_) { | |
| 477 DWORD result(::WaitForSingleObject(service_thread_, kShutdownIntervalMs)); | |
| 478 ASSERT1(result == WAIT_OBJECT_0); | |
| 479 ::CloseHandle(service_thread_); | |
| 480 service_thread_ = NULL; | |
| 481 } | |
| 482 | |
| 483 return m_status.dwWin32ExitCode; | |
| 484 } | |
| 485 | |
| 486 HANDLE service_thread_; // The service thread provided by the SCM. | |
| 487 bool is_service_com_server_; // True if the service is being invoked by COM. | |
| 488 | |
| 489 // Service shut down wait timeout. The main thread waits for the service | |
| 490 // thread to exit, after the service stops. | |
| 491 static const DWORD kShutdownIntervalMs = 1000L * 30; // 30 seconds. | |
| 492 | |
| 493 // Service idle check timeout. The service shuts down itself after startup. | |
| 494 static const DWORD kIdleCheckIntervalMs = 1000L * 30; // 30 seconds. | |
| 495 | |
| 496 // Service failover constants. | |
| 497 // | |
| 498 // Time after which the SCM resets the failure count to zero if there are | |
| 499 // no failures. | |
| 500 static const DWORD kResetPeriodSec = 60 * 60 * 24; // 1 day. | |
| 501 | |
| 502 // Time to wait before performing the specified action. | |
| 503 static const DWORD kActionDelayMs = 1000L * 60 * 15; // 15 minutes. | |
| 504 | |
| 505 DISALLOW_EVIL_CONSTRUCTORS(ServiceModule); | |
| 506 }; | |
| 507 | |
| 508 #pragma warning(pop) | |
| 509 | |
| 510 typedef ServiceModule<Update3ServiceMode> Update3ServiceModule; | |
| 511 typedef ServiceModule<UpdateMediumServiceMode> UpdateMediumServiceModule; | |
| 512 | |
| 513 } // namespace omaha | |
| 514 | |
| 515 #endif // OMAHA_SERVICE_SERVICE_MAIN_H_ | |
| OLD | NEW |