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

Side by Side Diff: service/service_main.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 | « service/build.scons ('k') | service/service_main.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 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_
OLDNEW
« no previous file with comments | « service/build.scons ('k') | service/service_main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698