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