Index: setup/setup_service.h |
diff --git a/setup/setup_service.h b/setup/setup_service.h |
deleted file mode 100644 |
index d44fc2253cca41531e3812a34babde510b003e68..0000000000000000000000000000000000000000 |
--- a/setup/setup_service.h |
+++ /dev/null |
@@ -1,540 +0,0 @@ |
-// Copyright 2007-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. |
-// ======================================================================== |
-// |
-// Sets up and controls the Google Update service. |
- |
-// TODO(omaha3): Consolidate all the service related code into one file in base |
-// and one file in service. |
- |
-#ifndef OMAHA_SETUP_SETUP_SERVICE_H_ |
-#define OMAHA_SETUP_SETUP_SERVICE_H_ |
- |
-#include <windows.h> |
-#include "base/basictypes.h" |
-#include "omaha/base/constants.h" |
-#include "omaha/base/debug.h" |
-#include "omaha/base/error.h" |
-#include "omaha/base/logging.h" |
-#include "omaha/base/path.h" |
-#include "omaha/base/safe_format.h" |
-#include "omaha/base/scoped_any.h" |
-#include "omaha/base/service_utils.h" |
-#include "omaha/base/system_info.h" |
-#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/service/service_main.h" |
- |
-namespace omaha { |
- |
-const uint32 kMaxQueryConfigBufferBytes = 8 * 1024; |
- |
-template <typename T> |
-class SetupService { |
- public: |
- static HRESULT StartService() { |
- OPT_LOG(L1, (_T("[StartService]"))); |
- |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); |
- if (!scm) { |
- return HRESULTFromLastError(); |
- } |
- |
- CString service_name(T::GetCurrentServiceName()); |
- scoped_service service(::OpenService(get(scm), |
- service_name, |
- SERVICE_QUERY_STATUS | SERVICE_START)); |
- if (!service) { |
- return HRESULTFromLastError(); |
- } |
- |
- SERVICE_STATUS status = {0}; |
- if (::QueryServiceStatus(get(service), &status)) { |
- if (status.dwCurrentState == SERVICE_RUNNING || |
- status.dwCurrentState == SERVICE_START_PENDING) { |
- SETUP_LOG(L1, (_T("[QueryServiceStatus][Service already running][%u]"), |
- status.dwCurrentState)); |
- return S_OK; |
- } |
- } |
- |
- // Start the service. |
- if (::StartService(get(service), 0, NULL)) { |
- SETUP_LOG(L1, (_T("[StartService][started]"))); |
- return S_OK; |
- } |
- |
- HRESULT hr = HRESULTFromLastError(); |
- ASSERT1(hr != HRESULT_FROM_WIN32(ERROR_SERVICE_ALREADY_RUNNING)); |
- if (hr == HRESULT_FROM_WIN32(ERROR_SERVICE_ALREADY_RUNNING)) { |
- SETUP_LOG(L1, (_T("[StartService][ERROR_SERVICE_ALREADY_RUNNING]"))); |
- return S_OK; |
- } |
- |
- return hr; |
- } |
- |
- static HRESULT StopService() { |
- SETUP_LOG(L1, (_T("[StopService]"))); |
- |
- CString service_name(T::GetCurrentServiceName()); |
- return ServiceInstall::StopService(service_name); |
- } |
- |
- static HRESULT InstallService(const TCHAR* file_path) { |
- ASSERT1(file_path); |
- |
- // Append the arguments to be passed to the service entry point. |
- |
- CString service_cmd_line(file_path); |
- CommandLineBuilder builder(T::commandline_mode()); |
- SafeCStringAppendFormat(&service_cmd_line, _T(" %s"), |
- builder.GetCommandLineArgs()); |
- |
- SETUP_LOG(L2, (_T("[service command line][%s]"), service_cmd_line)); |
- |
- HRESULT hr = DoInstallService(service_cmd_line); |
- if (FAILED(hr)) { |
- SETUP_LOG(LE, (_T("[DoInstallService failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- VERIFY1(SUCCEEDED(SetDescription(GetServiceDescription()))); |
- VERIFY1(SUCCEEDED(SetDelayedAutoStart())); |
- |
- return InstallCOMService(); |
- } |
- |
- // Uninstalls the service by: |
- // 1. unregistering it |
- // 2. deleting it from SCM if needed. |
- static HRESULT UninstallService() { |
- SETUP_LOG(L3, (_T("[UninstallService][%s]"), T::GetCurrentServiceName())); |
- |
- HRESULT hr = StopService(); |
- if (FAILED(hr)) { |
- SETUP_LOG(LW, (_T("[StopService failed][0x%08x]"), hr)); |
- ASSERT1(HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) == hr); |
- } |
- |
- VERIFY1(SUCCEEDED(UninstallCOMService())); |
- |
- hr = DeleteService(); |
- if (FAILED(hr)) { |
- OPT_LOG(LEVEL_ERROR, (_T("[Can't delete the service][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- return S_OK; |
- } |
- |
- static bool IsServiceInstalled() { |
- return ServiceInstall::IsServiceInstalled(T::GetCurrentServiceName()); |
- } |
- |
- private: |
- static HRESULT InstallCOMService() { |
- SETUP_LOG(L1, (_T("[InstallCOMService]"))); |
- |
- HRESULT hr = ServiceModule<T>().RegisterCOMService(); |
- |
- // We reset the _pAtlModule to allow for the case where multiple instances |
- // of ServiceModule are installed serially. |
- _pAtlModule = NULL; |
- |
- return hr; |
- } |
- |
- static HRESULT UninstallCOMService() { |
- SETUP_LOG(L1, (_T("[UninstallCOMService]"))); |
- |
- HRESULT hr = ServiceModule<T>().UnregisterCOMService(); |
- |
- // We reset the _pAtlModule to allow for the case where multiple instances |
- // of ServiceModule are uninstalled serially. |
- _pAtlModule = NULL; |
- |
- return hr; |
- } |
- |
- static HRESULT DoInstallService(const TCHAR* service_cmd_line) { |
- SETUP_LOG(L1, (_T("[DoInstallService][%s]"), service_cmd_line)); |
- |
- ASSERT1(service_cmd_line); |
- |
- if (IsServiceInstalled()) { |
- // Lightweight upgrade of existing service. |
- HRESULT hr = UpgradeService(service_cmd_line); |
- ASSERT(SUCCEEDED(hr), (_T("[UpgradeService failed][0x%x]"), hr)); |
- if (SUCCEEDED(hr)) { |
- return hr; |
- } |
- |
- // Delete the previous version of the service. Then create a new service |
- // name, and fall through to install that. |
- VERIFY1(SUCCEEDED(DeleteService())); |
- VERIFY1(SUCCEEDED(CreateAndSetVersionedServiceNameInRegistry())); |
- ASSERT1(!IsServiceInstalled()); |
- } |
- |
- return DoInstallNewService(service_cmd_line); |
- } |
- |
- static HRESULT DoInstallNewService(const TCHAR* service_cmd_line) { |
- ASSERT1(service_cmd_line); |
- |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); |
- if (!scm) { |
- const DWORD error = ::GetLastError(); |
- SETUP_LOG(LE, (_T("[Failed to open SC Manager][%u]"), error)); |
- return HRESULT_FROM_WIN32(error); |
- } |
- |
- CString service_name(T::GetCurrentServiceName()); |
- CString service_display_name(GetCurrentServiceDisplayName()); |
- scoped_service service(::CreateService(get(scm), |
- service_name, |
- service_display_name, |
- SERVICE_ALL_ACCESS, |
- SERVICE_WIN32_OWN_PROCESS, |
- T::service_start_type(), |
- SERVICE_ERROR_NORMAL, |
- service_cmd_line, |
- NULL, |
- NULL, |
- _T("RPCSS\0"), |
- NULL, |
- NULL)); |
- if (!service) { |
- const DWORD error = ::GetLastError(); |
- SETUP_LOG(LE, (_T("[CreateService failed][%u]"), error)); |
- return HRESULT_FROM_WIN32(error); |
- } |
- SETUP_LOG(L1, (_T("[DoInstallNewService][service installed]"))); |
- return S_OK; |
- } |
- |
- static bool IsServiceCorrectlyConfigured(const TCHAR* service_cmd_line) { |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)); |
- if (!scm) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[Failed to open SC Manager][0x%x]"), hr)); |
- return false; |
- } |
- |
- CString service_name(T::GetCurrentServiceName()); |
- scoped_service service(::OpenService(get(scm), |
- service_name, |
- SERVICE_QUERY_CONFIG)); |
- if (!service) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[OpenService SERVICE_QUERY_CONFIG fail][0x%x]"), hr)); |
- return false; |
- } |
- |
- // ::QueryServiceConfig expects a buffer of at most 8K bytes, according to |
- // documentation. While the size of the buffer can be dynamically computed, |
- // we just assume the maximum size for simplicity. |
- uint8 buffer[kMaxQueryConfigBufferBytes] = { 0 }; |
- DWORD bytes_needed_ignored = 0; |
- QUERY_SERVICE_CONFIG* service_config = |
- reinterpret_cast<QUERY_SERVICE_CONFIG*>(buffer); |
- if (!::QueryServiceConfig(get(service), |
- service_config, |
- sizeof(buffer), |
- &bytes_needed_ignored)) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[QueryServiceConfig failed][0x%x]"), hr)); |
- return false; |
- } |
- |
- bool does_service_cmd_line_match = false; |
- if (service_config->lpBinaryPathName == NULL || service_cmd_line == NULL) { |
- does_service_cmd_line_match = |
- (service_config->lpBinaryPathName == service_cmd_line); |
- } else { |
- does_service_cmd_line_match = |
- !_tcsicmp(service_config->lpBinaryPathName, service_cmd_line); |
- } |
- return service_config->dwServiceType == SERVICE_WIN32_OWN_PROCESS && |
- service_config->dwStartType == T::service_start_type() && |
- service_config->dwErrorControl == SERVICE_ERROR_NORMAL && |
- does_service_cmd_line_match; |
- } |
- |
- static HRESULT UpgradeService(const TCHAR* service_cmd_line) { |
- ASSERT1(service_cmd_line); |
- ASSERT1(IsServiceInstalled()); |
- |
- if (IsServiceCorrectlyConfigured(service_cmd_line)) { |
- return S_OK; |
- } |
- |
- // Modify the configuration of the existing service. |
- HRESULT hr(StopService()); |
- if (FAILED(hr)) { |
- SETUP_LOG(LE, (_T("[Can't stop the service][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); |
- if (!scm) { |
- const DWORD error = ::GetLastError(); |
- SETUP_LOG(LE, (_T("[Failed to open SC Manager][%u]"), error)); |
- return HRESULT_FROM_WIN32(error); |
- } |
- |
- CString service_name(T::GetCurrentServiceName()); |
- scoped_service service(::OpenService(get(scm), |
- service_name, |
- SERVICE_CHANGE_CONFIG)); |
- if (!service) { |
- const DWORD error = ::GetLastError(); |
- SETUP_LOG(LE, (_T("[Failed to open service for update][%u]"), error)); |
- return HRESULT_FROM_WIN32(error); |
- } |
- |
- if (!::ChangeServiceConfig(get(service), |
- SERVICE_WIN32_OWN_PROCESS, |
- T::service_start_type(), |
- SERVICE_ERROR_NORMAL, |
- service_cmd_line, |
- NULL, |
- NULL, |
- NULL, |
- NULL, |
- NULL, |
- NULL)) { |
- const DWORD error = ::GetLastError(); |
- SETUP_LOG(LE, (_T("[Failed to change service config][%u]"), error)); |
- return HRESULT_FROM_WIN32(error); |
- } |
- |
- SETUP_LOG(L3, (_T("[ChangeServiceConfig succeeded]"))); |
- return S_OK; |
- } |
- |
- static bool IsDelayedAutoStart() { |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)); |
- if (!scm) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[SC_MANAGER_CONNECT failed][0x%x]"), hr)); |
- return false; |
- } |
- |
- CString name(T::GetCurrentServiceName()); |
- scoped_service service(::OpenService(get(scm), name, SERVICE_QUERY_CONFIG)); |
- if (!service) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[SERVICE_QUERY_CONFIG failed][%s][0x%x]"), name, hr)); |
- return false; |
- } |
- |
- uint8 buffer[kMaxQueryConfigBufferBytes] = { 0 }; |
- DWORD bytes_needed_ignored = 0; |
- SERVICE_DELAYED_AUTO_START_INFO* service_config = |
- reinterpret_cast<SERVICE_DELAYED_AUTO_START_INFO*>(buffer); |
- if (!::QueryServiceConfig2(get(service), |
- SERVICE_CONFIG_DELAYED_AUTO_START_INFO, |
- buffer, |
- sizeof(buffer), |
- &bytes_needed_ignored)) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[Query SERVICE_CONFIG_DELAYED_AUTO_START_INFO failed]") |
- _T("[0x%x]"), hr)); |
- return false; |
- } |
- |
- return !!service_config->fDelayedAutostart; |
- } |
- |
- static HRESULT SetDelayedAutoStart() { |
- if (!SystemInfo::IsRunningOnVistaOrLater()) { |
- return S_OK; |
- } |
- |
- ASSERT1(IsServiceInstalled()); |
- |
- if (IsDelayedAutoStart()) { |
- return S_OK; |
- } |
- |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); |
- if (!scm) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[OpenSCManager failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- CString service_name(T::GetCurrentServiceName()); |
- scoped_service service(::OpenService(get(scm), |
- service_name, |
- SERVICE_CHANGE_CONFIG)); |
- if (!service) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[OpenService failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- SERVICE_DELAYED_AUTO_START_INFO auto_start_info = {TRUE}; |
- if (!::ChangeServiceConfig2(get(service), |
- SERVICE_CONFIG_DELAYED_AUTO_START_INFO, |
- &auto_start_info)) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[ChangeServiceConfig2 failed][0x%x]"), hr)); |
- return hr; |
- } |
- |
- SETUP_LOG(L3, (_T("[SetDelayedAutoStart succeeded]"))); |
- return S_OK; |
- } |
- |
- static HRESULT DeleteService() { |
- SETUP_LOG(L3, (_T("[DeleteService][%s]"), T::GetCurrentServiceName())); |
- |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); |
- if (!scm) { |
- return HRESULTFromLastError(); |
- } |
- scoped_service service(::OpenService(get(scm), |
- T::GetCurrentServiceName(), |
- SERVICE_CHANGE_CONFIG | DELETE)); |
- if (!service) { |
- return HRESULTFromLastError(); |
- } |
- |
- if (!::DeleteService(get(service))) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LW, (_T("[DeleteService failed][0x%x]"), hr)); |
- if (hr != HRESULT_FROM_WIN32(ERROR_SERVICE_MARKED_FOR_DELETE)) { |
- return hr; |
- } |
- } |
- |
- return S_OK; |
- } |
- |
- static bool DoesDescriptionMatch(const TCHAR* description) { |
- ASSERT1(description); |
- |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)); |
- if (!scm) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[SC_MANAGER_CONNECT failed][0x%x]"), hr)); |
- return false; |
- } |
- |
- CString name(T::GetCurrentServiceName()); |
- scoped_service service(::OpenService(get(scm), name, SERVICE_QUERY_CONFIG)); |
- if (!service) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[SERVICE_QUERY_CONFIG failed][%s][0x%x]"), name, hr)); |
- return false; |
- } |
- |
- uint8 buffer[kMaxQueryConfigBufferBytes] = { 0 }; |
- DWORD bytes_needed_ignored = 0; |
- SERVICE_DESCRIPTION* service_config = |
- reinterpret_cast<SERVICE_DESCRIPTION*>(buffer); |
- if (!::QueryServiceConfig2(get(service), |
- SERVICE_CONFIG_DESCRIPTION, |
- buffer, |
- sizeof(buffer), |
- &bytes_needed_ignored)) { |
- HRESULT hr = HRESULTFromLastError(); |
- SETUP_LOG(LE, (_T("[QuerySERVICE_CONFIG_DESCRIPTION failed][0x%x]"), hr)); |
- return false; |
- } |
- |
- if (service_config->lpDescription == NULL || description == NULL) { |
- return (service_config->lpDescription == description); |
- } |
- |
- return !_tcsicmp(service_config->lpDescription, description); |
- } |
- |
- static HRESULT SetDescription(const TCHAR* description) { |
- ASSERT1(description); |
- |
- if (DoesDescriptionMatch(description)) { |
- return S_OK; |
- } |
- |
- scoped_service scm(::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)); |
- if (!scm) { |
- return HRESULTFromLastError(); |
- } |
- |
- CString name(T::GetCurrentServiceName()); |
- |
- // Opening the service with less rights fails the ChangeServiceConfig2 call |
- // with E_ACCESSDENIED. |
- scoped_service service(::OpenService(get(scm), name, SERVICE_ALL_ACCESS)); |
- if (!service) { |
- return HRESULTFromLastError(); |
- } |
- SERVICE_DESCRIPTION info = { const_cast<TCHAR*>(description) }; |
- if (!::ChangeServiceConfig2(get(service), |
- SERVICE_CONFIG_DESCRIPTION, |
- &info)) { |
- return HRESULTFromLastError(); |
- } |
- SETUP_LOG(L3, (_T("[service description changed successfully]"))); |
- return S_OK; |
- } |
- |
- static CString GetCurrentServiceDisplayName() { |
- CORE_LOG(L3, (_T("[GetCurrentServiceDisplayName]"))); |
- |
- CString product_name; |
- VERIFY1(product_name.LoadString(IDS_PRODUCT_DISPLAY_NAME)); |
- |
- CString display_name; |
- display_name.FormatMessage(IDS_SERVICE_DISPLAY_NAME, product_name); |
- display_name.AppendFormat(_T(" (%s)"), T::GetCurrentServiceName()); |
- return display_name; |
- } |
- |
- static CString GetServiceDescription() { |
- // TODO(omaha3): Do we need a different service description for the medium |
- // service? |
- |
- CString company_name; |
- VERIFY1(company_name.LoadString(IDS_FRIENDLY_COMPANY_NAME)); |
- |
- CString service_description; |
- service_description.FormatMessage(IDS_SERVICE_DESCRIPTION, company_name); |
- return service_description; |
- } |
- |
- static HRESULT CreateAndSetVersionedServiceNameInRegistry() { |
- CORE_LOG(L3, (_T("CreateAndSetVersionedServiceNameInRegistry"))); |
- return goopdate_utils::CreateAndSetVersionedNameInRegistry(true, |
- T::default_name(), T::reg_name()); |
- } |
- |
- friend class SetupServiceTest; |
- friend class CoreUtilsTest; |
- |
- DISALLOW_IMPLICIT_CONSTRUCTORS(SetupService); |
-}; |
- |
-typedef SetupService<Update3ServiceMode> SetupUpdate3Service; |
-typedef SetupService<UpdateMediumServiceMode> SetupUpdateMediumService; |
- |
-} // namespace omaha |
- |
-#endif // OMAHA_SETUP_SETUP_SERVICE_H_ |