| 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
|
|
|