Index: setup/setup_google_update.cc |
diff --git a/setup/setup_google_update.cc b/setup/setup_google_update.cc |
deleted file mode 100644 |
index aaee71bb00c3b17c2b5654fd1a9f5c6b05e2ef8c..0000000000000000000000000000000000000000 |
--- a/setup/setup_google_update.cc |
+++ /dev/null |
@@ -1,866 +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. |
-// ======================================================================== |
- |
-#include "omaha/setup/setup_google_update.h" |
- |
-#include <msi.h> |
-#include <atlpath.h> |
-#include <vector> |
-#include "base/basictypes.h" |
-#include "omaha/base/app_util.h" |
-#include "omaha/base/atlregmapex.h" |
-#include "omaha/base/const_object_names.h" |
-#include "omaha/base/const_utils.h" |
-#include "omaha/base/constants.h" |
-#include "omaha/base/debug.h" |
-#include "omaha/base/error.h" |
-#include "omaha/base/file.h" |
-#include "omaha/base/highres_timer-win32.h" |
-#include "omaha/base/logging.h" |
-#include "omaha/base/omaha_version.h" |
-#include "omaha/base/path.h" |
-#include "omaha/base/reg_key.h" |
-#include "omaha/base/scoped_any.h" |
-#include "omaha/base/service_utils.h" |
-#include "omaha/base/utils.h" |
-#include "omaha/base/user_info.h" |
-#include "omaha/common/command_line_builder.h" |
-#include "omaha/common/config_manager.h" |
-#include "omaha/common/const_cmd_line.h" |
-#include "omaha/common/const_goopdate.h" |
-#include "omaha/common/goopdate_utils.h" |
-#include "omaha/common/scheduled_task_utils.h" |
-#include "omaha/setup/setup_metrics.h" |
-#include "omaha/setup/setup_service.h" |
- |
-namespace omaha { |
- |
-namespace { |
- |
-#ifdef _DEBUG |
-HRESULT VerifyCOMLocalServerRegistration(bool is_machine) { |
-// TODO(omaha3): Implement this for Omaha 3. Specifically, this code assumes |
-// Setup is running from the installed location, which is no longer true. |
-#if 0 |
- // Validate the following: |
- // * LocalServer32 under CLSID_OnDemandMachineAppsClass or |
- // CLSID_OnDemandUserAppsClass should be ...Google\Update\GoogleUpdate.exe. |
- // * InProcServer32 under CLSID of IID_IGoogleUpdate should be |
- // ...Google\Update\{version}\goopdate.dll. |
- // * ProxyStubClsid32 under IGoogleUpdate interface should be the CLSID of the |
- // proxy, which is IID_IGoogleUpdate. |
- |
- CString base_clsid_key(goopdate_utils::GetHKRoot()); |
- base_clsid_key += _T("\\Software\\Classes\\CLSID\\"); |
- CString ondemand_clsid_key(base_clsid_key); |
- ondemand_clsid_key += GuidToString(is_machine ? |
- __uuidof(OnDemandMachineAppsClass) : |
- __uuidof(OnDemandUserAppsClass)); |
- CString local_server_key(ondemand_clsid_key + _T("\\LocalServer32")); |
- CString installed_server; |
- ASSERT1(SUCCEEDED(RegKey::GetValue(local_server_key, |
- NULL, |
- &installed_server))); |
- ASSERT1(!installed_server.IsEmpty()); |
- |
- CString expected_server(app_util::GetModulePath(NULL)); |
- EnclosePath(&expected_server); |
- ASSERT1(!expected_server.IsEmpty()); |
- SETUP_LOG(L3, (_T("[installed_server=%s][expected_server=%s]"), |
- installed_server, expected_server)); |
- ASSERT1(installed_server == expected_server); |
- |
- const GUID proxy_clsid = PROXY_CLSID_IS; |
- CString ondemand_proxy_clsid_key(base_clsid_key); |
- ondemand_proxy_clsid_key += GuidToString(proxy_clsid); |
- CString inproc_server_key(ondemand_proxy_clsid_key + _T("\\InProcServer32")); |
- ASSERT1(SUCCEEDED(RegKey::GetValue(inproc_server_key, |
- NULL, |
- &installed_server))); |
- ASSERT1(!installed_server.IsEmpty()); |
- expected_server = app_util::GetCurrentModulePath(); |
- ASSERT1(!expected_server.IsEmpty()); |
- SETUP_LOG(L3, (_T("[installed proxy=%s][expected proxy=%s]"), |
- installed_server, expected_server)); |
- ASSERT1(installed_server == expected_server); |
- |
- CString igoogleupdate_interface_key(goopdate_utils::GetHKRoot()); |
- igoogleupdate_interface_key += _T("\\Software\\Classes\\Interface\\"); |
- igoogleupdate_interface_key += GuidToString(__uuidof(IGoogleUpdate)); |
- igoogleupdate_interface_key += _T("\\ProxyStubClsid32"); |
- CString proxy_interface_value; |
- ASSERT1(SUCCEEDED(RegKey::GetValue(igoogleupdate_interface_key, |
- NULL, |
- &proxy_interface_value))); |
- ASSERT1(!proxy_interface_value.IsEmpty()); |
- ASSERT1(proxy_interface_value == GuidToString(proxy_clsid)); |
-#else |
- UNREFERENCED_PARAMETER(is_machine); |
-#endif |
- return S_OK; |
-} |
-#endif |
- |
-HRESULT RegisterOrUnregisterService(bool reg, CString service_path) { |
- EnclosePath(&service_path); |
- |
- CommandLineBuilder builder(reg ? COMMANDLINE_MODE_SERVICE_REGISTER : |
- COMMANDLINE_MODE_SERVICE_UNREGISTER); |
- CString cmd_line = builder.GetCommandLineArgs(); |
- return RegisterOrUnregisterExe(service_path, cmd_line); |
-} |
- |
-} // namespace |
- |
-SetupGoogleUpdate::SetupGoogleUpdate(bool is_machine) |
- : is_machine_(is_machine), |
- extra_code1_(S_OK) |
-#ifdef _DEBUG |
- , have_called_uninstall_previous_versions_(false) |
-#endif |
-{ // NOLINT |
- this_version_ = GetVersionString(); |
-} |
- |
-SetupGoogleUpdate::~SetupGoogleUpdate() { |
- SETUP_LOG(L2, (_T("[SetupGoogleUpdate::~SetupGoogleUpdate]"))); |
-} |
- |
-// TODO(omaha): Add a VerifyInstall() method that can be called by /handoff |
-// instances to verify the installation and call FinishInstall() if it fails. |
- |
-// Assumes the caller is ensuring this is the only running instance of setup. |
-// The original process holds the lock while it waits for this one to complete. |
-HRESULT SetupGoogleUpdate::FinishInstall() { |
- SETUP_LOG(L2, (_T("[SetupGoogleUpdate::FinishInstall]"))); |
- |
- HRESULT hr = InstallRegistryValues(); |
- if (FAILED(hr)) { |
- SETUP_LOG(LE, (_T("[InstallRegistryValues failed][0x%08x]"), hr)); |
- if (E_ACCESSDENIED == hr) { |
- return GOOPDATE_E_ACCESSDENIED_SETUP_REG_ACCESS; |
- } |
- return hr; |
- } |
- |
- hr = InstallLaunchMechanisms(); |
- if (FAILED(hr)) { |
- SETUP_LOG(LE, (_T("[InstallLaunchMechanisms failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- hr = InstallMsiHelper(); |
- if (FAILED(hr)) { |
- SETUP_LOG(L1, (_T("[InstallMsiHelper failed][0x%08x]"), hr)); |
- // TODO(omaha): Retry on ERROR_INSTALL_ALREADY_RUNNING like InstallerWrapper |
- // if we move helper MSI installation after app installation. |
- ASSERT1(HRESULT_FROM_WIN32(ERROR_INSTALL_SERVICE_FAILURE) == hr || |
- HRESULT_FROM_WIN32(ERROR_INSTALL_ALREADY_RUNNING) == hr); |
- } |
- |
- hr = RegisterOrUnregisterCOMLocalServer(true); |
- if (FAILED(hr)) { |
- OPT_LOG(LW, (_T("[RegisterOrUnregisterCOMLocalServer failed][0x%x]"), hr)); |
- |
- // Fall through. Omaha will attempt to install using the in-proc mode. |
- } |
- |
- ASSERT1(SUCCEEDED(VerifyCOMLocalServerRegistration(is_machine_))); |
- |
- // We would prefer to uninstall previous versions last, but the web plugin |
- // requires that the old plugin is uninstalled before installing the new one. |
- VERIFY1(SUCCEEDED(UninstallPreviousVersions())); |
- |
- // Writing this value indicates that this Omaha version was successfully |
- // installed. This is an artifact of Omaha 2 when pv was set earlier in Setup. |
- CString reg_update = ConfigManager::Instance()->registry_update(is_machine_); |
- hr = RegKey::SetValue(reg_update, kRegValueInstalledVersion, this_version_); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- // Delete the "LastChecked" registry value after a successful install or |
- // update so that Omaha checks for updates soon after the install. This |
- // helps detecting a heart beat from the new version sooner as well as |
- // avoiding deferring application updates for too long in the case where both |
- // Omaha and application updates are available. |
- RegKey::DeleteValue(reg_update, kRegValueLastChecked); |
- |
- return S_OK; |
-} |
- |
-// Version values are written at the end of setup, not here. |
-HRESULT SetupGoogleUpdate::InstallRegistryValues() { |
- OPT_LOG(L3, (_T("[SetupGoogleUpdate::InstallRegistryValues]"))); |
- |
- const ConfigManager* cm = ConfigManager::Instance(); |
- const TCHAR* keys[] = { cm->registry_google(is_machine_), |
- cm->registry_update(is_machine_), |
- cm->registry_client_state(is_machine_), |
- cm->registry_clients(is_machine_), |
- cm->registry_clients_goopdate(is_machine_), |
- cm->registry_client_state_goopdate(is_machine_), |
- }; |
- |
- HRESULT hr = RegKey::CreateKeys(keys, arraysize(keys)); |
- if (FAILED(hr)) { |
- OPT_LOG(LE, (_T("[Failed to create reg keys][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- if (is_machine_) { |
- hr = CreateClientStateMedium(); |
- if (FAILED(hr)) { |
- SETUP_LOG(L3, (_T("[CreateClientStateMedium failed][0x%08x]"), hr)); |
- return hr; |
- } |
- } |
- |
- CString shell_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_); |
- if (shell_path.IsEmpty() || !File::Exists(shell_path)) { |
- SETUP_LOG(LE, (_T("[Failed to get valid shell path]"))); |
- return E_FAIL; |
- } |
- hr = RegKey::SetValue(cm->registry_update(is_machine_), |
- kRegValueInstalledPath, |
- shell_path); |
- if (FAILED(hr)) { |
- SETUP_LOG(LE, (_T("[Failed to write shell path][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- ASSERT1(!this_version_.IsEmpty()); |
- |
- const CString omaha_clients_key_path = |
- cm->registry_clients_goopdate(is_machine_); |
- |
- // Set the version so the constant shell will know which version to use. |
- // TODO(omaha3): This should be the atomic switch of the version, but it must |
- // be called before registering the COM servers because GoogleUpdate.exe needs |
- // the pv to find goopdate.dll. We may need to support rolling this back. |
- hr = RegKey::SetValue(omaha_clients_key_path, |
- kRegValueProductVersion, |
- this_version_); |
- if (FAILED(hr)) { |
- SETUP_LOG(LE, (_T("[Failed to set version in registry][0x%08x]"), hr)); |
- if (E_ACCESSDENIED == hr) { |
- return GOOPDATE_E_ACCESSDENIED_SETUP_REG_ACCESS; |
- } |
- return hr; |
- } |
- |
- // Write Omaha's localized name to the registry. During installation, this |
- // will use the installation language. For self-updates, it will use the |
- // user's/Local System's language. |
- CString omaha_name; |
- if (!omaha_name.LoadString(IDS_PRODUCT_DISPLAY_NAME)) { |
- ASSERT1(false); |
- omaha_name = kAppName; |
- } |
- VERIFY1(SUCCEEDED(RegKey::SetValue(omaha_clients_key_path, |
- kRegValueAppName, |
- omaha_name))); |
- |
- // Set pv in ClientState for consistency. Optional, so ignore errors. |
- const CString omaha_client_state_key_path = |
- cm->registry_client_state_goopdate(is_machine_); |
- VERIFY1(SUCCEEDED(RegKey::SetValue(omaha_client_state_key_path, |
- kRegValueProductVersion, |
- this_version_))); |
- |
- if (is_machine_) { |
- VERIFY1(SUCCEEDED(goopdate_utils::EnableSEHOP(true))); |
- } |
- |
- return S_OK; |
-} |
- |
-// Creates the ClientStateMedium key and adds ACLs that allows authenticated |
-// users to read and write values in its subkeys. |
-// Since this key is not as secure as other keys, the supported values must be |
-// limited and the use of them must be carefully designed. |
-HRESULT SetupGoogleUpdate::CreateClientStateMedium() { |
- ASSERT1(is_machine_); |
- |
- // Authenticated non-admins may read, write, and create values. |
- const ACCESS_MASK kNonAdminAccessMask = KEY_READ | KEY_SET_VALUE; |
- // The override privileges apply to all subkeys and values but not to the |
- // ClientStateMedium key itself. |
- const uint8 kAceFlags = |
- CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE; |
- |
- const CString key_full_name = |
- ConfigManager::Instance()->machine_registry_client_state_medium(); |
- HRESULT hr = RegKey::CreateKey(key_full_name); |
- if (FAILED(hr)) { |
- SETUP_LOG(LE, (_T("[Create ClientStateMedium failed][0x%08x]"), hr)); |
- return hr; |
- } |
- |
- // GetNamedSecurityInfo requires the key name start with "MACHINE". |
- // TODO(omaha): Replace AddAllowedAce or add an override that takes a handle |
- // instead of a name to eliminate this issue. |
- CString compatible_key_name = key_full_name; |
- VERIFY1(1 == compatible_key_name.Replace(MACHINE_KEY_NAME, _T("MACHINE"))); |
- |
- hr = AddAllowedAce(compatible_key_name, |
- SE_REGISTRY_KEY, |
- Sids::Interactive(), |
- kNonAdminAccessMask, |
- kAceFlags); |
- if (FAILED(hr)) { |
- SETUP_LOG(LE, (_T("[AddAllowedAce failed][%s][0x%08x]"), |
- key_full_name, hr)); |
- return hr; |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT SetupGoogleUpdate::InstallLaunchMechanisms() { |
- SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallLaunchMechanisms]"))); |
- if (is_machine_) { |
- HRESULT hr = InstallMachineLaunchMechanisms(); |
- if (FAILED(hr)) { |
- SETUP_LOG(LE, (_T("[InstallMachineLaunchMechanisms fail][0x%08x]"), hr)); |
- return hr; |
- } |
- } else { |
- HRESULT hr = InstallUserLaunchMechanisms(); |
- if (FAILED(hr)) { |
- SETUP_LOG(LE, (_T("[InstallUserLaunchMechanisms failed][0x%08x]"), hr)); |
- return hr; |
- } |
- } |
- |
- return S_OK; |
-} |
- |
-void SetupGoogleUpdate::UninstallLaunchMechanisms() { |
- SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallLaunchMechanisms]"))); |
- if (is_machine_) { |
- CString current_dir = app_util::GetModuleDirectory(NULL); |
- CString service_path = ConcatenatePath(current_dir, kServiceFileName); |
- |
- VERIFY1(SUCCEEDED(RegisterOrUnregisterService(false, service_path))); |
- } else { |
- // We only need to do this in case of the user goopdate, as |
- // there is no machine Run at startup installation. |
- VERIFY1(SUCCEEDED(ConfigureUserRunAtStartup(false))); // delete entry |
- } |
- |
- VERIFY1(SUCCEEDED(scheduled_task_utils::UninstallGoopdateTasks(is_machine_))); |
-} |
- |
-HRESULT SetupGoogleUpdate::InstallScheduledTask() { |
- CString exe_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_); |
- |
- HighresTimer metrics_timer; |
- const ULONGLONG install_task_start_ms = metrics_timer.GetElapsedMs(); |
- |
- HRESULT hr = scheduled_task_utils::InstallGoopdateTasks(exe_path, |
- is_machine_); |
- |
- if (SUCCEEDED(hr)) { |
- const ULONGLONG install_task_end_ms = metrics_timer.GetElapsedMs(); |
- ASSERT1(install_task_end_ms >= install_task_start_ms); |
- metric_setup_install_task_ms.AddSample( |
- install_task_end_ms - install_task_start_ms); |
- ++metric_setup_install_task_succeeded; |
- } else { |
- OPT_LOG(LEVEL_ERROR, (_T("[Install task failed][0x%08x]"), hr)); |
- metric_setup_install_task_error = hr; |
- } |
- |
- return hr; |
-} |
- |
-// Assumes the any existing service instance has been stopped |
-// TODO(omaha): Provide service_hr and task_hr failures in a ping. |
-// They are no longer being provided in the URL. |
-HRESULT SetupGoogleUpdate::InstallMachineLaunchMechanisms() { |
- SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallMachineLaunchMechanisms]"))); |
- ++metric_setup_install_service_task_total; |
- |
- // Install the service and scheduled task. Failing to install both will |
- // fail setup. |
- OPT_LOG(L1, (_T("[Installing service]"))); |
- HighresTimer metrics_timer; |
- |
- HRESULT service_hr = RegisterOrUnregisterService(true, |
- goopdate_utils::BuildGoogleUpdateExePath(is_machine_)); |
- ASSERT(SUCCEEDED(service_hr), (_T("[registration err][0x%x]"), service_hr)); |
- |
- if (SUCCEEDED(service_hr)) { |
- metric_setup_install_service_ms.AddSample( |
- metrics_timer.GetElapsedMs()); |
- ++metric_setup_install_service_succeeded; |
- } else { |
- metric_setup_install_service_failed_ms.AddSample( |
- metrics_timer.GetElapsedMs()); |
- OPT_LOG(LEVEL_ERROR, (_T("[Install service failed][0x%08x]"), service_hr)); |
- metric_setup_install_service_error = service_hr; |
- } |
- |
- HRESULT task_hr = InstallScheduledTask(); |
- |
- if (FAILED(service_hr) && FAILED(task_hr)) { |
- ++metric_setup_install_service_and_task_failed; |
- extra_code1_ = task_hr; |
- return service_hr; |
- } |
- |
-// TODO(omaha3): Setup does not know about OEM mode. Figure out a |
-// different way to do this. Maybe just verify that both are installed. |
-#if 0 |
- if (args_->is_oem_set) { |
- // OEM installs are on clean systems in a controlled environment. We expect |
- // both mechanisms to install. |
- if (FAILED(service_hr)) { |
- return service_hr; |
- } |
- if (FAILED(task_hr)) { |
- return task_hr; |
- } |
- } |
-#endif |
- |
- if (SUCCEEDED(service_hr) && SUCCEEDED(task_hr)) { |
- ++metric_setup_install_service_and_task_succeeded; |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT SetupGoogleUpdate::InstallUserLaunchMechanisms() { |
- SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallUserLaunchMechanisms]"))); |
- |
- HRESULT run_hr = ConfigureUserRunAtStartup(true); // install |
- ASSERT(SUCCEEDED(run_hr), (_T("ConfigureRunAtStartup 0x%x"), run_hr)); |
- |
- HRESULT task_hr = InstallScheduledTask(); |
- ASSERT(SUCCEEDED(task_hr), (_T("InstallScheduledTask 0x%x"), task_hr)); |
- |
- if (FAILED(run_hr) && FAILED(task_hr)) { |
- // We need atleast one launch mechanism. |
- extra_code1_ = task_hr; |
- return run_hr; |
- } |
- |
- return S_OK; |
-} |
- |
-// Sets a value in the Run key in the user registry to start the core. |
-HRESULT SetupGoogleUpdate::ConfigureUserRunAtStartup(bool install) { |
- SETUP_LOG(L3, (_T("SetupGoogleUpdate::ConfigureUserRunAtStartup"))); |
- // Always send false argument as this method is only called for user |
- // goopdate installs. |
- CString core_cmd = BuildCoreProcessCommandLine(); |
- return ConfigureRunAtStartup(USER_KEY_NAME, kRunValueName, core_cmd, install); |
-} |
- |
-HRESULT SetupGoogleUpdate::RegisterOrUnregisterCOMLocalServer(bool reg) { |
- SETUP_LOG(L3, (_T("[SetupGoogleUpdate::RegisterOrUnregisterCOMLocalServer]") |
- _T("[%d]"), reg)); |
- const CString google_update_path = |
- goopdate_utils::BuildGoogleUpdateExePath(is_machine_); |
- CString register_cmd; |
- register_cmd.Format(_T("/%s"), reg ? kCmdRegServer : kCmdUnregServer); |
- HRESULT hr = RegisterOrUnregisterExe(google_update_path, register_cmd); |
- if (FAILED(hr)) { |
- SETUP_LOG(LE, (_T("[RegisterOrUnregisterExe failed][0x%08x]"), hr)); |
- return hr; |
- } |
- return S_OK; |
-} |
- |
-// Assumes that the MSI is in the current directory. |
-// To debug MSI failures, use the following statement: |
-// ::MsiEnableLog(INSTALLLOGMODE_VERBOSE, _T("C:\\msi.log"), NULL); |
-HRESULT SetupGoogleUpdate::InstallMsiHelper() { |
- SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallMsiHelper]"))); |
- if (!is_machine_) { |
- return S_OK; |
- } |
- |
- ++metric_setup_helper_msi_install_total; |
- HighresTimer metrics_timer; |
- |
- const CPath msi_path(BuildSupportFileInstallPath(kHelperInstallerName)); |
- ASSERT1(File::Exists(msi_path)); |
- |
- // Setting INSTALLUILEVEL_NONE causes installation to be silent and not |
- // create a restore point. |
- ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); |
- |
- // Try a normal install. |
- UINT res = ::MsiInstallProduct(msi_path, kMsiSuppressAllRebootsCmdLine); |
- if (ERROR_PRODUCT_VERSION == res) { |
- // The product may already be installed. Force a reinstall of everything. |
- SETUP_LOG(L3, (_T("[ERROR_PRODUCT_VERSION returned - forcing reinstall]"))); |
- CString force_install_cmd_line; |
- force_install_cmd_line.Format(_T("REINSTALL=ALL REINSTALLMODE=vamus %s"), |
- kMsiSuppressAllRebootsCmdLine); |
- res = ::MsiInstallProduct(msi_path, force_install_cmd_line); |
- } |
- |
- HRESULT hr = HRESULT_FROM_WIN32(res); |
- if (FAILED(hr)) { |
- SETUP_LOG(L1, (_T("[MsiInstallProduct failed][0x%08x][%u]"), hr, res)); |
- return hr; |
- } |
- |
- metric_setup_helper_msi_install_ms.AddSample(metrics_timer.GetElapsedMs()); |
- ++metric_setup_helper_msi_install_succeeded; |
- return S_OK; |
-} |
- |
-// The MSI is uninstalled. |
-// TODO(omaha): Make sure this works after deleting the MSI. |
-HRESULT SetupGoogleUpdate::UninstallMsiHelper() { |
- SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallMsiHelper]"))); |
- if (!is_machine_) { |
- return S_OK; |
- } |
- |
- // Setting INSTALLUILEVEL_NONE causes installation to be silent and not |
- // create a restore point. |
- ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL); |
- |
- // MSDN says that eInstallState must be INSTALLSTATE_DEFAULT in order for the |
- // command line to be used. Therefore, instead of using INSTALLSTATE_ABSENT |
- // to uninstall, we must pass REMOVE=ALL in the command line. |
- CString uninstall_cmd_line; |
- uninstall_cmd_line.Format(_T("REMOVE=ALL %s"), |
- kMsiSuppressAllRebootsCmdLine); |
- UINT res = ::MsiConfigureProductEx(kHelperInstallerProductGuid, |
- INSTALLLEVEL_DEFAULT, |
- INSTALLSTATE_DEFAULT, |
- uninstall_cmd_line); |
- |
- // Ignore the product not currently installed result. |
- if ((ERROR_SUCCESS != res) && (ERROR_UNKNOWN_PRODUCT != res)) { |
- HRESULT hr = HRESULT_FROM_WIN32(res); |
- if (FAILED(hr)) { |
- SETUP_LOG(L1, (_T("[MsiInstallProduct failed][0x%08x][%u]"), hr, res)); |
- return hr; |
- } |
- } |
- |
- return S_OK; |
-} |
- |
-HRESULT SetupGoogleUpdate::InstallBrowserPlugins() { |
- SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallBrowserPlugins]"))); |
- ASSERT1(have_called_uninstall_previous_versions_); |
- // Failure of registration of optional components is acceptable in release |
- // builds. |
- HRESULT hr = S_OK; |
- |
- CString plugin_path = |
- BuildSupportFileInstallPath(UPDATE_PLUGIN_FILENAME); |
- hr = RegisterDll(plugin_path); |
- if (FAILED(hr)) { |
- SETUP_LOG(L1, (_T("[Register plugin DLL failed][0x%08x]"), hr)); |
- } |
- |
-// TODO(omaha): Enable when we ship the BHO. |
-#if 0 |
- // Only install the BHO for machine installs. There is no corresponding HKCU |
- // registration for BHOs. |
- if (is_machine_) { |
- CString goopdate_bho_proxy_path = BuildSupportFileInstallPath(BHO_FILENAME); |
- hr = RegisterDll(goopdate_bho_proxy_path); |
- if (FAILED(hr)) { |
- SETUP_LOG(L1, (_T("[Register bho_proxy DLL failed][0x%08x]"), hr)); |
- } |
- } |
-#endif |
- |
- return hr; |
-} |
- |
-HRESULT SetupGoogleUpdate::UninstallBrowserPlugins() { |
- SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallBrowserPlugins]"))); |
- // Unregistration. Failure is acceptable in release builds. |
- HRESULT hr = S_OK; |
- |
- CString plugin_path = |
- BuildSupportFileInstallPath(UPDATE_PLUGIN_FILENAME); |
- hr = UnregisterDll(plugin_path); |
- if (FAILED(hr)) { |
- SETUP_LOG(L1, (_T("[Unregister plugin DLL failed][0x%08x]"), hr)); |
- } |
- |
-// TODO(omaha): Enable when we ship the BHO. |
-#if 0 |
- if (is_machine_) { |
- CString goopdate_bho_proxy_path = BuildSupportFileInstallPath(BHO_FILENAME); |
- hr = UnregisterDll(goopdate_bho_proxy_path); |
- if (FAILED(hr)) { |
- SETUP_LOG(L1, (_T("[Unregister bho_proxy DLL failed][0x%08x]"), hr)); |
- } |
- } |
-#endif |
- |
- return hr; |
-} |
- |
-CString SetupGoogleUpdate::BuildSupportFileInstallPath( |
- const CString& filename) const { |
- SETUP_LOG(L3, (_T("[SetupGoogleUpdate::BuildSupportFileInstallPath][%s]"), |
- filename)); |
- CPath install_file_path = goopdate_utils::BuildInstallDirectory( |
- is_machine_, |
- this_version_); |
- VERIFY1(install_file_path.Append(filename)); |
- |
- return install_file_path; |
-} |
- |
-CString SetupGoogleUpdate::BuildCoreProcessCommandLine() const { |
- CString google_update_path = |
- goopdate_utils::BuildGoogleUpdateExePath(is_machine_); |
- CommandLineBuilder builder(COMMANDLINE_MODE_CORE); |
- return builder.GetCommandLine(google_update_path); |
-} |
- |
-HRESULT SetupGoogleUpdate::UninstallPreviousVersions() { |
-#ifdef _DEBUG |
- have_called_uninstall_previous_versions_ = true; |
-#endif |
- |
- VERIFY1(SUCCEEDED( |
- scheduled_task_utils::UninstallLegacyGoopdateTasks(is_machine_))); |
- |
- CString install_path( |
- is_machine_ ? ConfigManager::Instance()->GetMachineGoopdateInstallDir() : |
- ConfigManager::Instance()->GetUserGoopdateInstallDir()); |
- SETUP_LOG(L1, (_T("[SetupGoogleUpdate::UninstallPreviousVersions][%s][%s]"), |
- install_path, this_version_)); |
- // An empty install_path can be disastrous as it will start deleting from the |
- // current directory. |
- ASSERT1(!install_path.IsEmpty()); |
- if (install_path.IsEmpty()) { |
- return E_UNEXPECTED; |
- } |
- |
- // In the Google\\Update directory, run over all files and directories. |
- WIN32_FIND_DATA file_data = {0}; |
- CPath find_files(install_path); |
- VERIFY1(find_files.Append(_T("*.*"))); |
- |
- scoped_hfind find_handle(::FindFirstFile(find_files, &file_data)); |
- ASSERT1(find_handle); |
- if (!find_handle) { |
- // We should have found ".", "..", and our versioned directory. |
- DWORD err = ::GetLastError(); |
- SETUP_LOG(LE, (L"[Subdirs not found under dir][%s][%d]", find_files, err)); |
- return HRESULT_FROM_WIN32(err); |
- } |
- |
- // Find the rightmost path element of the download directory. |
- CPath download_dir(OMAHA_REL_DOWNLOAD_STORAGE_DIR); |
- download_dir.StripPath(); |
- |
- BOOL found_next = TRUE; |
- for (; found_next; found_next = ::FindNextFile(get(find_handle), |
- &file_data)) { |
- CPath file_or_directory(install_path); |
- VERIFY1(file_or_directory.Append(file_data.cFileName)); |
- if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { |
- // Do not delete the shell as it is used by all versions. |
- if (_tcsicmp(file_data.cFileName, kOmahaShellFileName)) { |
- DeleteBeforeOrAfterReboot(file_or_directory); |
- } |
- } else if (_tcscmp(file_data.cFileName, _T("..")) && |
- _tcscmp(file_data.cFileName, _T(".")) && |
- _tcsicmp(file_data.cFileName, this_version_) && |
- _tcsicmp(file_data.cFileName, download_dir)) { |
- // Unregister the previous version OneClick if it exists. Ignore |
- // failures. The file is named npGoogleOneClick*.dll. |
- CPath old_oneclick(file_or_directory); |
- VERIFY1(old_oneclick.Append(ONECLICK_PLUGIN_NAME _T("*.dll"))); |
- WIN32_FIND_DATA old_oneclick_file_data = {}; |
- scoped_hfind found_oneclick(::FindFirstFile(old_oneclick, |
- &old_oneclick_file_data)); |
- if (found_oneclick) { |
- CPath old_oneclick_file(file_or_directory); |
- VERIFY1(old_oneclick_file.Append(old_oneclick_file_data.cFileName)); |
- VERIFY1(SUCCEEDED(UnregisterDll(old_oneclick_file))); |
- } |
- |
- // Unregister the previous version of the plugin if it exists. Ignore |
- // failures. The file is named npGoogleUpdate*.dll. |
- CPath old_plugin(file_or_directory); |
- VERIFY1(old_plugin.Append(UPDATE_PLUGIN_NAME _T("*.dll"))); |
- WIN32_FIND_DATA old_plugin_file_data = {}; |
- scoped_hfind found_plugin(::FindFirstFile(old_plugin, |
- &old_plugin_file_data)); |
- if (found_plugin) { |
- CPath old_plugin_file(file_or_directory); |
- VERIFY1(old_plugin_file.Append(old_plugin_file_data.cFileName)); |
- VERIFY1(SUCCEEDED(UnregisterDll(old_plugin_file))); |
- } |
- |
- |
- if (is_machine_) { |
- // TODO(omaha): Enable when we ship the BHO. |
- /* |
- // BHO is only installed for the machine case. |
- // Unregister the previous version BHO if it exists. Ignore failures. |
- CPath old_bho_dll(file_or_directory); |
- VERIFY1(old_bho_dll.Append(BHO_FILENAME)); |
- if (File::Exists(old_bho_dll)) { |
- if (FAILED(UnregisterDll(old_bho_dll))) { |
- SETUP_LOG(LW, (L"[UnregisterDll() failed][%s]", old_bho_dll)); |
- } |
- } |
- */ |
- } |
- // Delete entire sub-directory. |
- DeleteBeforeOrAfterReboot(file_or_directory); |
- } |
- } |
- |
- if (!found_next) { |
- DWORD err = ::GetLastError(); |
- if (ERROR_NO_MORE_FILES != err) { |
- SETUP_LOG(LE, (L"[::FindNextFile() failed][%d]", err)); |
- return HRESULT_FROM_WIN32(err); |
- } |
- } |
- |
- // Clean up existing machine ID and user ID since they are no longer used. |
- // Ignore failures as they may not be present and we may not have permission |
- // to HKLM. |
- const TCHAR* const kRegValueMachineId = _T("mi"); |
- const TCHAR* const kRegValueUserId = _T("ui"); |
- RegKey::DeleteValue(ConfigManager::Instance()->machine_registry_update(), |
- kRegValueMachineId); |
- RegKey::DeleteValue( |
- ConfigManager::Instance()->registry_update(is_machine_), |
- kRegValueUserId); |
- |
- return S_OK; |
-} |
- |
-void SetupGoogleUpdate::Uninstall() { |
- OPT_LOG(L1, (_T("[SetupGoogleUpdate::Uninstall]"))); |
- |
- HRESULT hr = UninstallBrowserPlugins(); |
- if (FAILED(hr)) { |
- SETUP_LOG(LW, (_T("[UninstallBrowserPlugins failed][0x%08x]"), hr)); |
- ASSERT1(HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND) == hr); |
- } |
- |
- // If running from the installed location instead of a temporary location, |
- // we assume that Omaha had been properly installed and can verify the COM |
- // registration. |
- if (goopdate_utils::IsRunningFromOfficialGoopdateDir(is_machine_)) { |
- ASSERT1(SUCCEEDED(VerifyCOMLocalServerRegistration(is_machine_))); |
- } |
- |
- hr = RegisterOrUnregisterCOMLocalServer(false); |
- if (FAILED(hr)) { |
- SETUP_LOG(LW, |
- (_T("[RegisterOrUnregisterCOMLocalServer failed][0x%08x]"), hr)); |
- ASSERT1(GOOGLEUPDATE_E_DLL_NOT_FOUND == hr || |
- HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr); |
- } |
- |
- hr = UninstallMsiHelper(); |
- if (FAILED(hr)) { |
- SETUP_LOG(L1, (_T("[UninstallMsiHelper failed][0x%08x]"), hr)); |
- ASSERT1(HRESULT_FROM_WIN32(ERROR_INSTALL_SERVICE_FAILURE) == hr); |
- } |
- |
- UninstallLaunchMechanisms(); |
- |
- // Remove everything under top level Google Update registry key. |
- hr = DeleteRegistryKeys(); |
- ASSERT1(SUCCEEDED(hr) || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr); |
-} |
- |
-// Also deletes the main Google Update key if there is nothing in it. |
-HRESULT SetupGoogleUpdate::DeleteRegistryKeys() { |
- OPT_LOG(L3, (_T("[SetupGoogleUpdate::DeleteRegistryKeys]"))); |
- |
- if (is_machine_) { |
- VERIFY1(SUCCEEDED(goopdate_utils::EnableSEHOP(false))); |
- } |
- |
- CString root_key = ConfigManager::Instance()->registry_update(is_machine_); |
- ASSERT1(!root_key.IsEmpty()); |
- |
- RegKey root; |
- HRESULT hr = root.Open(root_key); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- std::vector<CString> sub_keys; |
- size_t num_keys = root.GetSubkeyCount(); |
- for (size_t i = 0; i < num_keys; ++i) { |
- CString sub_key_name; |
- hr = root.GetSubkeyNameAt(i, &sub_key_name); |
- ASSERT1(hr == S_OK); |
- if (SUCCEEDED(hr)) { |
- sub_keys.push_back(sub_key_name); |
- } |
- } |
- |
- ASSERT1(num_keys == sub_keys.size()); |
- // Delete all the sub keys of the root key. |
- for (size_t i = 0; i < num_keys; ++i) { |
- VERIFY1(SUCCEEDED(root.RecurseDeleteSubKey(sub_keys[i]))); |
- } |
- |
- // Now delete all the values of the root key. |
- // The Last* values are not deleted. |
- // TODO(omaha3): The above is a temporary fix for bug 1539293. Need a better |
- // long-term solution in Omaha 3. |
- size_t num_values = root.GetValueCount(); |
- std::vector<CString> value_names; |
- for (size_t i = 0; i < num_values; ++i) { |
- CString value_name; |
- DWORD type = 0; |
- hr = root.GetValueNameAt(i, &value_name, &type); |
- ASSERT1(hr == S_OK); |
- // TODO(omaha): Remove kRegValueLast* once we have an install API. |
- if (SUCCEEDED(hr)) { |
- if (value_name != kRegValueUserId && |
- value_name != kRegValueLastInstallerResult && |
- value_name != kRegValueLastInstallerError && |
- value_name != kRegValueLastInstallerExtraCode1 && |
- value_name != kRegValueLastInstallerResultUIString && |
- value_name != kRegValueLastInstallerSuccessLaunchCmdLine) { |
- value_names.push_back(value_name); |
- } |
- } |
- } |
- |
- for (size_t i = 0; i < value_names.size(); ++i) { |
- VERIFY1(SUCCEEDED(root.DeleteValue(value_names[i]))); |
- } |
- |
- if (0 == root.GetValueCount() && 0 == root.GetSubkeyCount()) { |
- VERIFY1(SUCCEEDED(RegKey::DeleteKey(root_key, false))); |
- } |
- |
- return S_OK; |
-} |
- |
-} // namespace omaha |