| Index: service/service_main.h
|
| diff --git a/service/service_main.h b/service/service_main.h
|
| deleted file mode 100644
|
| index 93b471f5053ae7d57c408a59de66d1257216419c..0000000000000000000000000000000000000000
|
| --- a/service/service_main.h
|
| +++ /dev/null
|
| @@ -1,515 +0,0 @@
|
| -// Copyright 2006-2010 Google Inc.
|
| -//
|
| -// Licensed under the Apache License, Version 2.0 (the "License");
|
| -// you may not use this file except in compliance with the License.
|
| -// You may obtain a copy of the License at
|
| -//
|
| -// http://www.apache.org/licenses/LICENSE-2.0
|
| -//
|
| -// Unless required by applicable law or agreed to in writing, software
|
| -// distributed under the License is distributed on an "AS IS" BASIS,
|
| -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| -// See the License for the specific language governing permissions and
|
| -// limitations under the License.
|
| -// ========================================================================
|
| -
|
| -// The service is a bootstrap for a local system process to start
|
| -// when the computer starts. The service shuts itself down in 30 seconds.
|
| -//
|
| -// The service can be started in one of two modes:
|
| -// * As a regular service, typically at system startup.
|
| -// * As a COM service, typically by an Omaha client using IGoogleUpdateCore.
|
| -// The COM case is distinguished from the regular service case by registering a
|
| -// ServiceParameters command line in the AppID registration.
|
| -//
|
| -// In all cases, the service initializes COM, and allows for IGoogleUpdateCore
|
| -// clients to connect to the service. In the regular service case, the service
|
| -// shuts down after a small idle check timeout, provided that there are no COM
|
| -// clients connected. In the COM server case, and in the case where there are
|
| -// COM clients connected in the regular service case, the service will shut down
|
| -// when the last client disconnects.
|
| -//
|
| -// To be exact, the service will initiate shutdown in all cases when the ATL
|
| -// module count drops to zero.
|
| -//
|
| -// ATL does not allow for directly reusing the delayed COM shutdown mechanism
|
| -// available for Local servers. The assumption likely being that services run
|
| -// forever. Since we do not want our service to run forever, we override some
|
| -// of the functions to get the same effect.
|
| -
|
| -#ifndef OMAHA_SERVICE_SERVICE_MAIN_H_
|
| -#define OMAHA_SERVICE_SERVICE_MAIN_H_
|
| -
|
| -#include <atlbase.h>
|
| -#include <atlcom.h>
|
| -#include "base/basictypes.h"
|
| -#include "base/scoped_ptr.h"
|
| -#include "omaha/base/atlregmapex.h"
|
| -#include "omaha/base/debug.h"
|
| -// Use client/resource.h because it does not use StringFormatter and some of the
|
| -// strings are only used during Setup, which is part of the client.
|
| -// TODO(omaha3): It is a little unexpected to access strings in a header. It
|
| -// would be nice to avoid that. Also, this file is included by both client
|
| -// (setup_service.cc) and server (goopdate.cc) code.
|
| -#include "omaha/client/resource.h"
|
| -#include "omaha/common/command_line_builder.h"
|
| -#include "omaha/common/const_cmd_line.h"
|
| -#include "omaha/common/const_goopdate.h"
|
| -#include "omaha/common/goopdate_utils.h"
|
| -#include "omaha/core/google_update_core.h"
|
| -#include "omaha/goopdate/google_update3.h"
|
| -#include "omaha/goopdate/non_localized_resource.h"
|
| -#include "omaha/goopdate/ondemand.h"
|
| -#include "omaha/goopdate/update3web.h"
|
| -#include "omaha/goopdate/worker.h"
|
| -#include "omaha/net/network_config.h"
|
| -
|
| -namespace omaha {
|
| -
|
| -class Update3ServiceMode {
|
| - public:
|
| - static CommandLineMode commandline_mode();
|
| - static CString reg_name();
|
| - static CString default_name();
|
| - static DWORD service_start_type();
|
| - static _ATL_OBJMAP_ENTRY* object_map();
|
| - static bool allow_access_from_medium();
|
| - static CString app_id_string();
|
| - static CString GetCurrentServiceName();
|
| - static HRESULT PreMessageLoop();
|
| -};
|
| -
|
| -class UpdateMediumServiceMode {
|
| - public:
|
| - static CommandLineMode commandline_mode();
|
| - static CString reg_name();
|
| - static CString default_name();
|
| - static DWORD service_start_type();
|
| - static _ATL_OBJMAP_ENTRY* object_map();
|
| - static bool allow_access_from_medium();
|
| - static CString app_id_string();
|
| - static CString GetCurrentServiceName();
|
| - static HRESULT PreMessageLoop();
|
| -};
|
| -
|
| -#pragma warning(push)
|
| -// C4640: construction of local static object is not thread-safe
|
| -#pragma warning(disable : 4640)
|
| -
|
| -template <typename T>
|
| -class ServiceModule
|
| - : public CAtlServiceModuleT<ServiceModule<T>, IDS_SERVICE_NAME> {
|
| - public:
|
| - typedef CAtlServiceModuleT<ServiceModule, IDS_SERVICE_NAME> Base;
|
| -
|
| - DECLARE_REGISTRY_APPID_RESOURCEID_EX(IDR_GOOGLE_UPDATE3_SERVICE_APPID,
|
| - T::app_id_string())
|
| -
|
| - BEGIN_REGISTRY_MAP()
|
| - REGMAP_ENTRY(_T("DESCRIPTION"), _T("ServiceModule"))
|
| - REGMAP_ENTRY(_T("FILENAME"), kServiceFileName)
|
| - END_REGISTRY_MAP()
|
| -
|
| - ServiceModule()
|
| - : service_thread_(NULL),
|
| - is_service_com_server_(false) {
|
| - SERVICE_LOG(L1, (_T("[ServiceModule]")));
|
| - _tcscpy(m_szServiceName, T::GetCurrentServiceName());
|
| - }
|
| -
|
| - ~ServiceModule() {
|
| - SERVICE_LOG(L1, (_T("[~ServiceModule]")));
|
| - ASSERT1(!service_thread_);
|
| -
|
| - // ServiceModule is typically created on the stack. We cannot reset the
|
| - // _pAtlModule here, because objects are destroyed at destructor unwind
|
| - // time, and require access to the module.
|
| - }
|
| -
|
| - HRESULT InitializeSecurity() throw() {
|
| - SERVICE_LOG(L3, (_T("[InitializeSecurity]")));
|
| -
|
| - return InitializeServerSecurity(T::allow_access_from_medium());
|
| - }
|
| -
|
| - void ServiceMain(DWORD argc, LPTSTR* argv) throw() {
|
| - ASSERT1(argc <= 2);
|
| - is_service_com_server_ =
|
| - argc == 2 && !CString(argv[1]).CompareNoCase(kCmdLineServiceComServer);
|
| - SERVICE_LOG(L3, (_T("[ServiceMain][is_service_com_server_][%d]"),
|
| - is_service_com_server_));
|
| - Base::ServiceMain(argc, argv);
|
| - }
|
| -
|
| - HRESULT RegisterClassObjects(DWORD class_context,
|
| - DWORD flags) throw() {
|
| - SERVICE_LOG(L3, (_T("[RegisterClassObjects]")));
|
| - for (_ATL_OBJMAP_ENTRY* objmap_entry = T::object_map();
|
| - objmap_entry->pclsid != NULL;
|
| - objmap_entry++) {
|
| - HRESULT hr = objmap_entry->RegisterClassObject(class_context, flags);
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[RegisterClassObject failed][%s][0x%x]"),
|
| - GuidToString(*objmap_entry->pclsid), hr));
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - return S_OK;
|
| - }
|
| -
|
| - HRESULT RevokeClassObjects() throw() {
|
| - SERVICE_LOG(L3, (_T("[RevokeClassObjects]")));
|
| - for (_ATL_OBJMAP_ENTRY* objmap_entry = T::object_map();
|
| - objmap_entry->pclsid != NULL;
|
| - objmap_entry++) {
|
| - HRESULT hr = objmap_entry->RevokeClassObject();
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[RevokeClassObject failed][%s][0x%x]"),
|
| - GuidToString(*objmap_entry->pclsid), hr));
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - return S_OK;
|
| - }
|
| -
|
| - HRESULT RegisterServer(BOOL, const CLSID* = NULL) throw() {
|
| - SERVICE_LOG(L3, (_T("[RegisterServer]")));
|
| - for (_ATL_OBJMAP_ENTRY* objmap_entry = T::object_map();
|
| - objmap_entry->pclsid != NULL;
|
| - objmap_entry++) {
|
| - HRESULT hr = objmap_entry->pfnUpdateRegistry(TRUE);
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[pfnUpdateRegistry failed][%s][0x%x]"),
|
| - GuidToString(*objmap_entry->pclsid), hr));
|
| - return hr;
|
| - }
|
| -
|
| - hr = AtlRegisterClassCategoriesHelper(*objmap_entry->pclsid,
|
| - objmap_entry->pfnGetCategoryMap(),
|
| - TRUE);
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[RegisterServer fail][%s][0x%x]"),
|
| - GuidToString(*objmap_entry->pclsid), hr));
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - return S_OK;
|
| - }
|
| -
|
| - HRESULT UnregisterServer(BOOL, const CLSID* = NULL) throw() {
|
| - SERVICE_LOG(L3, (_T("[UnregisterServer]")));
|
| - for (_ATL_OBJMAP_ENTRY* objmap_entry = T::object_map();
|
| - objmap_entry->pclsid != NULL;
|
| - objmap_entry++) {
|
| - HRESULT hr = AtlRegisterClassCategoriesHelper(*objmap_entry->pclsid,
|
| - objmap_entry->pfnGetCategoryMap(),
|
| - FALSE);
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[RegisterServer fail][%s][0x%x]"),
|
| - GuidToString(*objmap_entry->pclsid), hr));
|
| - return hr;
|
| - }
|
| -
|
| - hr = objmap_entry->pfnUpdateRegistry(FALSE);
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[pfnUpdateRegistry failed][%s][0x%x]"),
|
| - GuidToString(*objmap_entry->pclsid), hr));
|
| - return hr;
|
| - }
|
| - }
|
| -
|
| - return S_OK;
|
| - }
|
| -
|
| - HRESULT RegisterCOMService() {
|
| - SERVICE_LOG(L3, (_T("[RegisterCOMService]")));
|
| - HRESULT hr = UpdateRegistryAppId(TRUE);
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[UpdateRegistryAppId failed][0x%x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - RegKey key_app_id;
|
| - hr = key_app_id.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE);
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[Could not open HKLM\\AppID][0x%x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - RegKey key;
|
| - hr = key.Create(key_app_id.Key(), GetAppIdT());
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[Fail open HKLM-AppID-%s][0x%x]"), GetAppId(), hr));
|
| - return hr;
|
| - }
|
| -
|
| - // m_szServiceName is set in the constructor.
|
| - hr = key.SetValue(_T("LocalService"), m_szServiceName);
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[Could not set LocalService value][0x%x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - // The SCM will pass this switch to ServiceMain() during COM activation.
|
| - hr = key.SetValue(_T("ServiceParameters"), kCmdLineServiceComServer);
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[Set ServiceParameters value failed][0x%x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - return RegisterServer(FALSE);
|
| - }
|
| -
|
| - HRESULT UnregisterCOMService() {
|
| - SERVICE_LOG(L3, (_T("[UnregisterCOMService]")));
|
| - HRESULT hr = UnregisterServer(FALSE);
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[UnregisterServer failed][0x%x]"), hr));
|
| - return hr;
|
| - }
|
| -
|
| - return UpdateRegistryAppId(FALSE);
|
| - }
|
| -
|
| - HRESULT PreMessageLoop(int show_cmd) {
|
| - UNREFERENCED_PARAMETER(show_cmd);
|
| -
|
| - SERVICE_LOG(L1, (_T("[PreMessageLoop]")));
|
| -
|
| - m_dwThreadID = ::GetCurrentThreadId();
|
| - service_thread_ = ::OpenThread(SYNCHRONIZE, false, m_dwThreadID);
|
| -
|
| - if (is_service_com_server_) {
|
| - return InitializeCOMServer();
|
| - }
|
| -
|
| - // This is the regular service case. Call T::PreMessageLoop() and exit.
|
| - SetServiceStatus(SERVICE_RUNNING);
|
| -
|
| - HRESULT hr = T::PreMessageLoop();
|
| - if (FAILED(hr)) {
|
| - SERVICE_LOG(LE, (_T("[T::PreMessageLoop() failed][0x%x]"), hr));
|
| - }
|
| -
|
| - SetServiceStatus(SERVICE_STOP_PENDING);
|
| -
|
| - // S_FALSE is returned to exit the service immediately.
|
| - return S_FALSE;
|
| - }
|
| -
|
| - HRESULT PostMessageLoop() {
|
| - SERVICE_LOG(L1, (_T("[PostMessageLoop]")));
|
| -
|
| - if (!is_service_com_server_) {
|
| - return S_OK;
|
| - }
|
| -
|
| - return Base::PostMessageLoop();
|
| - }
|
| -
|
| - int Main(int show_cmd) {
|
| - if (CAtlBaseModule::m_bInitFailed) {
|
| - SERVICE_LOG(LE, (_T("[CAtlBaseModule init failed]")));
|
| - return -1;
|
| - }
|
| -
|
| - return static_cast<int>(Start(show_cmd));
|
| - }
|
| -
|
| - // This is cloned from CAtlExeModuleT.Lock(). The one difference is the call
|
| - // to ::CoAddRefServerProcess(). See the description for Unlock() below for
|
| - // further information.
|
| - virtual LONG Lock() throw() {
|
| - ::CoAddRefServerProcess();
|
| - LONG retval = CComGlobalsThreadModel::Increment(&m_nLockCnt);
|
| - SERVICE_LOG(L3, (_T("[ServiceModule::Lock][%d]"), retval));
|
| - return retval;
|
| - }
|
| -
|
| - // This is cloned from CAtlExeModuleT.Unlock(). The differences are:
|
| - //
|
| - // * the call to ::CoReleaseServerProcess(), to ensure that the class
|
| - // factories are suspended once the lock count drops to zero. This fixes a
|
| - // a race condition where an activation request could come in in the middle
|
| - // of shutting down. This shutdown mechanism works with free threaded servers.
|
| - //
|
| - // There are race issues with the ATL delayed shutdown mechanism, hence the
|
| - // associated code has been eliminated, and we have an assert to make sure
|
| - // m_bDelayShutdown is not set.
|
| - //
|
| - // * the call to "OnStop()" instead of the "::PostThreadMessage(m_dwMainThre".
|
| - // OnStop() correctly sets the service status to SERVICE_STOP_PENDING, and
|
| - // posts a WM_QUIT to the service thread.
|
| - virtual LONG Unlock() throw() {
|
| - ASSERT1(!m_bDelayShutdown);
|
| -
|
| - ::CoReleaseServerProcess();
|
| - LONG retval = CComGlobalsThreadModel::Decrement(&m_nLockCnt);
|
| - SERVICE_LOG(L3, (_T("[ServiceModule::Unlock][%d]"), retval));
|
| -
|
| - if (retval == 0) {
|
| - OnStop();
|
| - }
|
| -
|
| - return retval;
|
| - }
|
| -
|
| - // This is cloned from CAtlExeModuleT.MonitorShutdown(). The only difference
|
| - // is the call to "OnStop()" instead of the
|
| - // "::PostThreadMessage(m_dwMainThreadID".
|
| - void MonitorShutdown() throw() {
|
| - SERVICE_LOG(L3, (_T("[MonitorShutdown]")));
|
| -
|
| - while (true) {
|
| - ::WaitForSingleObject(m_hEventShutdown, INFINITE);
|
| - SERVICE_LOG(L4, (_T("[Infinite Wait][%d][%d]"), m_bActivity, m_nLockCnt));
|
| -
|
| - DWORD wait = 0;
|
| - do {
|
| - m_bActivity = false;
|
| - wait = ::WaitForSingleObject(m_hEventShutdown, m_dwTimeOut);
|
| - } while (wait == WAIT_OBJECT_0);
|
| -
|
| - SERVICE_LOG(L4, (_T("[MonitorShutdown][%d][%d]"),
|
| - m_bActivity, m_nLockCnt));
|
| - if (!m_bActivity && m_nLockCnt == 0) {
|
| - ::CoSuspendClassObjects();
|
| - if (m_nLockCnt == 0) {
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - ::CloseHandle(m_hEventShutdown);
|
| - OnStop();
|
| - }
|
| -
|
| - // This is cloned from CAtlExeModuleT.StartMonitor().
|
| - HANDLE StartMonitor() throw() {
|
| - SERVICE_LOG(L3, (_T("[StartMonitor]")));
|
| - m_hEventShutdown = ::CreateEvent(NULL, false, false, NULL);
|
| - if (m_hEventShutdown == NULL) {
|
| - return NULL;
|
| - }
|
| -
|
| - DWORD thread_id(0);
|
| - HANDLE monitor = ::CreateThread(NULL, 0, MonitorProc, this, 0, &thread_id);
|
| - if (monitor == NULL) {
|
| - ::CloseHandle(m_hEventShutdown);
|
| - }
|
| -
|
| - return monitor;
|
| - }
|
| -
|
| - // This is cloned from CAtlExeModuleT.MonitorProc().
|
| - static DWORD WINAPI MonitorProc(void* pv) throw() {
|
| - SERVICE_LOG(L3, (_T("[MonitorProc]")));
|
| - ServiceModule* service_module = static_cast<ServiceModule*>(pv);
|
| - ASSERT1(service_module);
|
| -
|
| - service_module->MonitorShutdown();
|
| - return 0;
|
| - }
|
| -
|
| - private:
|
| - // Should only be called from the client, such as during Setup, since it only
|
| - // supports one language.
|
| - // Assumes the resources have been loaded.
|
| - static CString GetServiceDescription() {
|
| - CString company_name;
|
| - VERIFY1(company_name.LoadString(IDS_FRIENDLY_COMPANY_NAME));
|
| - CString description;
|
| - description.FormatMessage(IDS_SERVICE_DESCRIPTION, company_name);
|
| - return description;
|
| - }
|
| -
|
| - HRESULT InitializeCOMServer() {
|
| - SERVICE_LOG(L1, (_T("[InitializeCOMServer]")));
|
| -
|
| - // Initialize COM security right at the beginning, because Worker
|
| - // initialization can cause interface marshaling. The first few lines below
|
| - // are adapted from the beginning of CAtlServiceModuleT::PreMessageLoop().
|
| - ASSERT1(m_bService);
|
| - HRESULT hr = InitializeSecurity();
|
| - if (FAILED(hr)) {
|
| - return hr;
|
| - }
|
| -
|
| - DisableCOMExceptionHandling();
|
| -
|
| - NetworkConfigManager::set_is_machine(true);
|
| -
|
| - // Create NetworkConfigManager singleton by referencing it.
|
| - NetworkConfigManager::Instance();
|
| -
|
| - // Register and resume the COM class objects. We call the CAtlExeModuleT
|
| - // member instead of CAtlServiceModuleT, because the latter also tries to
|
| - // initialize security, which we have already done above.
|
| - return CAtlExeModuleT<ServiceModule>::PreMessageLoop(SW_HIDE);
|
| - }
|
| -
|
| - // When Start executes, it blocks on StartServiceCtrlDispatcher.
|
| - // Internally, the SCM creates a service thread which starts executing code
|
| - // specified by SERVICE_TABLE_ENTRY. The ATL code then calls PreMessageLoop
|
| - // and PostMessageLoop on this thread. When the service stops, the execution
|
| - // flow returns from StartServiceCtrlDispatcher and the main thread blocks
|
| - // waiting on the service thread to exit.
|
| - // Before synchronizing the main thread and the service thread, race condition
|
| - // resulted in http://b/1134747.
|
| - HRESULT Start(int show_cmd) {
|
| - SERVICE_LOG(L1, (_T("[Start]")));
|
| - UNREFERENCED_PARAMETER(show_cmd);
|
| -
|
| - SERVICE_TABLE_ENTRY st[] = {
|
| - { m_szServiceName, Base::_ServiceMain },
|
| - { NULL, NULL }
|
| - };
|
| -
|
| - m_status.dwWin32ExitCode = 0;
|
| - if (!::StartServiceCtrlDispatcher(st)) {
|
| - m_status.dwWin32ExitCode = ::GetLastError();
|
| - }
|
| -
|
| - if (service_thread_) {
|
| - DWORD result(::WaitForSingleObject(service_thread_, kShutdownIntervalMs));
|
| - ASSERT1(result == WAIT_OBJECT_0);
|
| - ::CloseHandle(service_thread_);
|
| - service_thread_ = NULL;
|
| - }
|
| -
|
| - return m_status.dwWin32ExitCode;
|
| - }
|
| -
|
| - HANDLE service_thread_; // The service thread provided by the SCM.
|
| - bool is_service_com_server_; // True if the service is being invoked by COM.
|
| -
|
| - // Service shut down wait timeout. The main thread waits for the service
|
| - // thread to exit, after the service stops.
|
| - static const DWORD kShutdownIntervalMs = 1000L * 30; // 30 seconds.
|
| -
|
| - // Service idle check timeout. The service shuts down itself after startup.
|
| - static const DWORD kIdleCheckIntervalMs = 1000L * 30; // 30 seconds.
|
| -
|
| - // Service failover constants.
|
| - //
|
| - // Time after which the SCM resets the failure count to zero if there are
|
| - // no failures.
|
| - static const DWORD kResetPeriodSec = 60 * 60 * 24; // 1 day.
|
| -
|
| - // Time to wait before performing the specified action.
|
| - static const DWORD kActionDelayMs = 1000L * 60 * 15; // 15 minutes.
|
| -
|
| - DISALLOW_EVIL_CONSTRUCTORS(ServiceModule);
|
| -};
|
| -
|
| -#pragma warning(pop)
|
| -
|
| -typedef ServiceModule<Update3ServiceMode> Update3ServiceModule;
|
| -typedef ServiceModule<UpdateMediumServiceMode> UpdateMediumServiceModule;
|
| -
|
| -} // namespace omaha
|
| -
|
| -#endif // OMAHA_SERVICE_SERVICE_MAIN_H_
|
|
|