15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/google_update_util.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/path_service.h" 12a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/kill.h" 13a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/launch.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h" 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_handle.h" 18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/win/win_util.h" 19effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/win/windows_version.h" 20effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/installer/util/browser_distribution.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/google_update_constants.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/google_update_settings.h" 23effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/installer/util/install_util.h" 24effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/installer/util/installation_state.h" 25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/installer/util/product.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::RegKey; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace google_update { 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kGoogleUpdateTimeoutMs = 20 * 1000; 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if Google Update is present at the given level. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsGoogleUpdatePresent(bool system_install) { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Using the existence of version key in the registry to decide. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GoogleUpdateSettings::GetGoogleUpdateVersion(system_install).IsValid(); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns GoogleUpdateSetup.exe's executable path at specified level. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// or an empty path if none is found. 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath GetGoogleUpdateSetupExe(bool system_install) { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RegKey update_key; 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (update_key.Open(root_key, kRegPathGoogleUpdate, KEY_QUERY_VALUE) == 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ERROR_SUCCESS) { 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 path_str; 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 version_str; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((update_key.ReadValue(kRegPathField, &path_str) == ERROR_SUCCESS) && 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (update_key.ReadValue(kRegGoogleUpdateVersion, &version_str) == 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ERROR_SUCCESS)) { 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::FilePath(path_str).DirName().Append(version_str). 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Append(kGoogleUpdateSetupExe); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::FilePath(); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If Google Update is present at system-level, sets |cmd_string| to the command 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// line to install Google Update at user-level and returns true. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Otherwise, clears |cmd_string| and returns false. 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GetUserLevelGoogleUpdateInstallCommandLine(base::string16* cmd_string) { 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmd_string->clear(); 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath google_update_setup( 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) GetGoogleUpdateSetupExe(true)); // system-level. 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!google_update_setup.empty()) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine cmd(google_update_setup); 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Appends "/install runtime=true&needsadmin=false /silent /nomitag". 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // NB: /nomitag needs to be at the end. 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Constants are found in code.google.com/p/omaha/common/const_cmd_line.h. 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmd.AppendArg("/install"); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The "&" can be used in base::LaunchProcess() without quotation 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (this is problematic only if run from command prompt). 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmd.AppendArg("runtime=true&needsadmin=false"); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmd.AppendArg("/silent"); 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cmd.AppendArg("/nomitag"); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *cmd_string = cmd.GetCommandLineString(); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return !cmd_string->empty(); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Launches command |cmd_string|, and waits for |timeout| milliseconds before 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// timing out. To wait indefinitely, one can set 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |timeout| to be base::TimeDelta::FromMilliseconds(INFINITE). 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true if this executes successfully. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns false if command execution fails to execute, or times out. 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool LaunchProcessAndWaitWithTimeout(const base::string16& cmd_string, 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta timeout) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = false; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::win::ScopedHandle process; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int exit_code = 0; 94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(0) << "Launching: " << cmd_string; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::LaunchProcess(cmd_string, base::LaunchOptions(), 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &process)) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PLOG(ERROR) << "Failed to launch (" << cmd_string << ")"; 981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else if (!base::WaitForExitCodeWithTimeout(process.Get(), &exit_code, 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci timeout)) { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The GetExitCodeProcess failed or timed-out. 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) <<"Command (" << cmd_string << ") is taking more than " 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << timeout.InMilliseconds() << " milliseconds to complete."; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (exit_code != 0) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Command (" << cmd_string << ") exited with code " 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << exit_code; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = true; 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return success; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool EnsureUserLevelGoogleUpdatePresent() { 115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) VLOG(0) << "Ensuring Google Update is present at user-level."; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = false; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (IsGoogleUpdatePresent(false)) { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = true; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 cmd_string; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!GetUserLevelGoogleUpdateInstallCommandLine(&cmd_string)) { 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Cannot find Google Update at system-level."; 1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Ideally we should return false. However, this case should not be 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // encountered by regular users, and developers (who often installs 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Chrome without Google Update) may be unduly impeded by this case. 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Therefore we return true. 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) success = true; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = LaunchProcessAndWaitWithTimeout(cmd_string, 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromMilliseconds(INFINITE)); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return success; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool UninstallGoogleUpdate(bool system_install) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool success = false; 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 cmd_string( 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GoogleUpdateSettings::GetUninstallCommandLine(system_install)); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (cmd_string.empty()) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = true; // Nothing to; vacuous success. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) success = LaunchProcessAndWaitWithTimeout(cmd_string, 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromMilliseconds(kGoogleUpdateTimeoutMs)); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return success; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid ElevateIfNeededToReenableUpdates() { 151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::FilePath chrome_exe; 152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!PathService::Get(base::FILE_EXE, &chrome_exe)) { 153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch NOTREACHED(); 154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 156effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch installer::ProductState product_state; 157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 158effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const bool system_install = !InstallUtil::IsPerUserInstall( 159effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch chrome_exe.value().c_str()); 160effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!product_state.Initialize(system_install, dist)) 161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::FilePath exe_path(product_state.GetSetupPath()); 163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (exe_path.empty() || !base::PathExists(exe_path)) { 164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch LOG(ERROR) << "Could not find setup.exe to reenable updates."; 165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 166effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 167effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 168effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch CommandLine cmd(exe_path); 169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch cmd.AppendSwitch(installer::switches::kReenableAutoupdates); 170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch installer::Product product(dist); 171effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch product.InitializeFromUninstallCommand(product_state.uninstall_command()); 172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch product.AppendProductFlags(&cmd); 173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (system_install) 174effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch cmd.AppendSwitch(installer::switches::kSystemLevel); 175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (product_state.uninstall_command().HasSwitch( 176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch installer::switches::kVerboseLogging)) { 177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch cmd.AppendSwitch(installer::switches::kVerboseLogging); 178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::LaunchOptions launch_options; 181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch launch_options.force_breakaway_from_job_ = true; 182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 183effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (base::win::GetVersion() >= base::win::VERSION_VISTA && 184effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::win::UserAccountControlIsEnabled()) { 185effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::LaunchElevatedProcess(cmd, launch_options, NULL); 186effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } else { 187effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::LaunchProcess(cmd, launch_options, NULL); 188effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 189effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 190effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace google_update 192